说到倍增LCA,我不得不想起的就是NOIP2013货车运输。这题的原题其实是UVA11354。当年向SKYDEC学习了一下写法,但是不求甚解,只知道做法却不太明白所以然。后来也碰到过好几次类似的。最近想做个总结,首先重写了一遍这题,用白书上的写法。
UVA11354 给一张无向图,给出若干询问,每次询问两点间的最小瓶颈路的最大边长。(最小瓶颈路,即,使两点间的路径上的最长边最短这样的路)
题解:由最小生成树的性质可以知道,瓶颈路一定是在最小生成树上的。先求出MST,然后转化成有根树。然后对于每两个点之间的路径的最大边,只需要通过倍增LCA求的时候,顺便维护maxcost表示最大边长即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int inf=(1<<30)-1; 5 struct edge{ 6 int x,y,v; 7 bool operator <(const edge &b) const { 8 return v<b.v; 9 } 10 }a[maxn<<1]; 11 int n,m; 12 struct node { 13 int to,v; 14 }; 15 vector<node> G[maxn]; 16 int f[maxn],d[maxn]; 17 int cost[maxn],fa[maxn]; 18 int anc[maxn][20],maxcost[maxn][20]; 19 int get(int x) { 20 return (x==f[x])?x:f[x]=get(f[x]); 21 } 22 void dfs(int x,int pre,int dep) { 23 d[x]=dep; 24 int sz=G[x].size(); 25 for(int i=0;i<sz;i++) { 26 node &e=G[x][i]; 27 int y=e.to,v=e.v; 28 if(y==pre) continue; 29 fa[y]=x;cost[y]=v; 30 dfs(y,x,dep+1); 31 } 32 } 33 void preprocess() { 34 for(int i=1;i<=n;i++) { 35 anc[i][0]=fa[i];maxcost[i][0]=cost[i]; 36 for(int j=1;(1<<j)<n;j++) anc[i][j]=-1; 37 } 38 for(int j=1;(1<<j)<n;j++) { 39 for(int i=1;i<=n;i++) { 40 if(~anc[i][j-1]) { 41 int u=anc[i][j-1]; 42 anc[i][j]=anc[u][j-1]; 43 maxcost[i][j]=max(maxcost[i][j-1],maxcost[u][j-1]); 44 } 45 } 46 } 47 } 48 int LCA(int p,int q) { 49 int k; 50 if(d[p]<d[q]) swap(p,q); 51 for(k=1;(1<<k)<=d[p];k++); 52 k--; 53 int ans=-inf; 54 for(int i=k;i>=0;i--) 55 if(d[p]-(1<<i)>=d[q]) { 56 ans=max(ans,maxcost[p][i]); 57 p=anc[p][i]; 58 } 59 if(p==q) return ans; 60 for(int i=k;i>=0;i--) 61 if(~anc[p][i] && anc[p][i]!=anc[q][i]) { 62 ans=max(ans,maxcost[p][i]);p=anc[p][i]; 63 ans=max(ans,maxcost[q][i]);q=anc[q][i]; 64 } 65 ans=max(ans,cost[p]); 66 ans=max(ans,cost[q]); 67 return ans;//LCA = fa[p] 68 } 69 70 71 int main() { 72 bool fir=1; 73 while(~scanf("%d%d",&n,&m)) { 74 if(fir) fir=0; 75 else printf("\n"); 76 for(int i=1;i<=m;i++) { 77 int x,y,v;scanf("%d%d%d",&x,&y,&v); 78 a[i]=(edge){x,y,v}; 79 } 80 sort(a+1,a+m+1); 81 for(int i=0;i<=n;i++) G[i].clear(),f[i]=i; 82 int cnt=0; 83 for(int i=1;i<=m;i++) { 84 int u=get(a[i].x),v=get(a[i].y); 85 if(u!=v) { 86 f[u]=v; 87 G[u].push_back((node){v,a[i].v}); 88 G[v].push_back((node){u,a[i].v}); 89 if(++cnt==n-1) break; 90 } 91 } 92 dfs(1,-1,0); 93 preprocess(); 94 int Q;scanf("%d",&Q); 95 while(Q--) { 96 int x,y;scanf("%d%d",&x,&y); 97 printf("%d\n",LCA(x,y)); 98 } 99 } 100 return 0; 101 }
HDU2586 感觉RXDoi的写法超级优秀啊……学习了一下
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=(1<<30)-1; 4 const int maxn=100010; 5 int IN(){ 6 int c,f,x; 7 while (!isdigit(c=getchar())&&c!='-');c=='-'?(f=1,x=0):(f=0,x=c-'0'); 8 while (isdigit(c=getchar())) x=(x<<1)+(x<<3)+c-'0';return !f?x:-x; 9 } 10 int n,m,x,y,z,T; 11 int head[maxn],tot; 12 struct data{ 13 int to,next,v; 14 }e[maxn<<1]; 15 int dep[maxn],dis[maxn]; 16 int pa[maxn][20]; 17 void init() { 18 memset(head,-1,sizeof(head));tot=0; 19 } 20 void Add(int x,int y,int v) { 21 e[tot]=(data){y,head[x],v};head[x]=tot++; 22 e[tot]=(data){x,head[y],v};head[y]=tot++; 23 } 24 void dfs(int x) { 25 for(int i=head[x],y;~i;i=e[i].next) { 26 if((y=e[i].to)==pa[x][0]) continue; 27 dep[y]=dep[x]+1;pa[y][0]=x; 28 dis[y]=dis[x]+e[i].v;dfs(y); 29 } 30 } 31 int LCA(int x,int y) { 32 if(dep[x]>dep[y]) swap(x,y); 33 for(int w=dep[y]-dep[x],i=0;w;w>>=1,i++) if(w&1) y=pa[y][i]; 34 if(x==y) return x; 35 for(int i=19;~i;i--) if(pa[x][i]!=pa[y][i]) x=pa[x][i],y=pa[y][i]; 36 return pa[x][0]; 37 } 38 void Main() { 39 n=IN();m=IN(); 40 init(); 41 for(int i=1;i<n;i++) { 42 x=IN(),y=IN(),z=IN(); 43 Add(x,y,z); 44 } 45 dep[1]=0;dfs(1); 46 for(int i=1;i<=n;i++) for(int j=1;j<20;j++) pa[i][j]=pa[pa[i][j-1]][j-1]; 47 while(m--) x=IN(),y=IN(),printf("%d\n",dis[x]+dis[y]-2*dis[LCA(x,y)]); 48 } 49 int main() 50 { 51 for(int T=IN();T--;) Main(); 52 return 0; 53 }