101889I (LCA的另一種實現)
阿新 • • 發佈:2018-12-13
題意: Q次詢問,每次詢問必須包含特定邊的最小生成樹。
思路: 考慮 最淳樸的最小生成樹,如果加了一條特定邊,肯定是構成了一個環,那麼環外的邊肯定是不變的,要不然,根本就不可能選外面的那些邊了, 所以我們現在就是求這個環上的最小 生成樹,肯定是找樹上之前的 兩個點之間的最大邊,刪掉就行了。
所以問題就變成了,求樹上 任意兩點之間的最大邊。
錯誤思路: 考慮尤拉序列中深度的屬性,想著可不可以求一個最大值。直接把邊權給兒子,詢問的時候直接查詢 最大值就好了。
錯誤樣例1: 找 3 4 之間的最大值,會把 5放進去,就很難受
錯誤樣例2:找 1 和 5 的最大值, dfs的時候,可能會很恐怖的先走 1234325, 所以本來不屬於路徑上的點也會被加進來
正確思路: 記錄 fa[i][j] //表示 的上面距離為 的祖先是誰
同樣記錄 dis[i][j] //表示 的上面距離為 範圍內的最大邊權
然後就是LCA的跳躍了
#include<bits/stdc++.h> using namespace std; typedef long long LL; #define rep(i,a,b) for(int i=a;i<b;++i) #define per(i,a,b) for(int i=b-1;i>=a;--i) map<pair<int,int>,int> id; const int N=1e5+10; int has[N*2]; struct Edge{ int u,v,w,nt; Edge(int _u=0,int _v=0,int _w=0,int _nt=0){ u=_u,v=_v,w=_w,nt=_nt; } }edge[N*4],e[N*4]; int head[N],cnt; void add_edge(int u,int v,int w){ edge[cnt]=Edge(u,v,w,head[u]); head[u]=cnt++; } int cmp(Edge a,Edge b){ return a.w<b.w; } int pre[N]; int find_rt(int x){ return pre[x]==x?x:pre[x]=find_rt(pre[x]); } int join(int u,int v){ int ru=find_rt(u),rv=find_rt(v); if(ru!=rv){ pre[ru]=rv; return 1; } return 0; } int dep[N]; int fa[N][20],dis[N][20]; void dfs(int u,int f,int w){ fa[u][0]=f; dis[u][0]=w; dep[u]=dep[f]+1; for(int i=head[u];i!=-1;i=edge[i].nt){ Edge& e=edge[i]; if(e.v==f)continue; dfs(e.v,u,e.w); } } int Log[N],mx_h; void QQQ(int n){ for(int j=1;(1<<j)<=n;j++){ for(int i=1;i<=n;i++){ int t=fa[i][j-1]; fa[i][j]=fa[t][j-1]; dis[i][j]=max(dis[i][j-1],dis[t][j-1]); } } mx_h=Log[n]; } //!!!特別注意次序,那個x,y一定要在最後才跳躍 int swim(int& x,int d){ int res=0; for(int i=0;i<=mx_h;i++){ if(d&(1<<i)){ res=max(res,dis[x][i]); x=fa[x][i]; } } return res; } int LCA(int x,int y){ if(dep[x]>dep[y])swap(x,y); int ans=swim(y,dep[y]-dep[x]); if(x==y)return ans;//如果x 就是Y的祖先,那麼久結束了 for(int i=mx_h;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ ans=max(ans,dis[x][i]); ans=max(ans,dis[y][i]); x=fa[x][i]; y=fa[y][i]; } } //printf("x:%d y:%d\n",x,y); ans=max(ans,dis[x][0]); ans=max(ans,dis[y][0]); return ans; } int main(){ Log[1]=0; rep(i,2,N)Log[i]=Log[i/2]+1; int n,m; scanf("%d %d",&n,&m); cnt=0; rep(i,0,n+1){ head[i]=-1; pre[i]=i; } rep(i,0,m){ int u,v,w; scanf("%d %d %d",&u,&v,&w); e[i]=Edge(u,v,w); } sort(e,e+m,cmp); rep(i,0,m)id[make_pair(e[i].u,e[i].v)]=i; int sum=0; rep(i,0,m){ Edge& ee=e[i]; if(join(ee.v,ee.u)){ sum+=ee.w; has[i]=1; add_edge(ee.u,ee.v,ee.w); add_edge(ee.v,ee.u,ee.w); } } dfs(1,0,0); QQQ(n); int q; scanf("%d",&q); rep(i,0,q){ int u,v; scanf("%d %d",&u,&v); int dd=id[make_pair(u,v)]; if(has[dd]){ printf("%d\n",sum); continue; } int w=LCA(u,v); printf("%d\n",sum-w+e[dd].w); } return 0; }