【LCA+MST】BZOJ3732-Network
【题目大意】
给你N个点的无向图 (1 <= N <= 15,000),记为:1…N。图中有M条边 (1<=M<=30,000) ,第j条边的长度:d_j (1<=d_j <=1,000,000,000)。现在有 K个询问 (1 < = K < = 15,000), 每个询问的格式是:A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
【思路】
显然,最小的最长边应该在MST上。先跑出MST,然后对于每个询问跑LCA,在跑LCA的过程中顺便处理最长边。
LCA处理最长边是第一次写,但是这种东西,yy一下就好了,和LCA里面的祖先数组长得是一样的啊……
【错误点】
LCA是最后a的父亲,所以我们还要比较一下a和它父亲的连边……
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=15000+50; 4 const int MAXM=30000+50; 5 const int DEG=20; 6 struct Edge 7 { 8 int u,v,w; 9 bool operator < (const Edge &x) const 10 { 11 return w<x.w; 12 }; 13 }; 14 Edge edge[MAXM]; 15 vector<Edge> E[MAXN]; 16 int n,m,k; 17 int u[MAXN],h[MAXN]; 18 int dep[MAXN],anc[MAXN][DEG],maxlen[MAXN][DEG]; 19 20 void addedge(int u,int v,int w) 21 { 22 E[u].push_back((Edge){u,v,w}); 23 E[v].push_back((Edge){v,u,w}); 24 } 25 26 int find(int x) 27 { 28 int r=x; 29 while (u[r]!=r) r=u[r]; 30 int tmp; 31 while (u[x]!=x) 32 { 33 tmp=u[x]; 34 u[x]=r; 35 x=tmp; 36 } 37 return r; 38 } 39 40 void union_set(int fa,int fb) 41 { 42 if (h[fa]>=h[fb]) 43 { 44 u[fb]=fa; 45 if (h[fa]==h[fb]) h[fa]++; 46 } 47 else u[fa]=fb; 48 } 49 50 void dfs(int u,int fa,int d) 51 { 52 anc[u][0]=fa; 53 dep[u]=d; 54 for (int i=0;i<E[u].size();i++) 55 { 56 int to=E[u][i].v; 57 if (to==fa) continue; 58 maxlen[to][0]=E[u][i].w; 59 dfs(to,u,d+1); 60 } 61 } 62 63 void getanc() 64 { 65 for (int i=1;i<DEG;i++) 66 for (int j=1;j<=n;j++) 67 { 68 anc[j][i]=anc[anc[j][i-1]][i-1]; 69 maxlen[j][i]=max(maxlen[j][i-1],maxlen[anc[j][i-1]][i-1]); 70 } 71 } 72 73 int swim(int x,int H,int &ret) 74 { 75 for (int i=0;H>0;i++) 76 { 77 if (H&1) ret=max(ret,maxlen[x][i]),x=anc[x][i];//swim过程中不要忘记更新ret 78 H/=2; 79 } 80 return x; 81 } 82 83 int lca(int a,int b) 84 { 85 int ret=-1; 86 if (dep[a]<dep[b]) swap(a,b); 87 a=swim(a,dep[a]-dep[b],ret); 88 if (a==b) return ret; 89 for (int i=DEG-1;i>=0;i--) 90 { 91 if (anc[a][i]!=anc[b][i]) 92 { 93 ret=max(ret,maxlen[a][i]); 94 a=anc[a][i]; 95 ret=max(ret,maxlen[b][i]); 96 b=anc[b][i]; 97 } 98 } 99 ret=max(ret,maxlen[a][0]);//最后一条和父亲的连边不要忘记 100 ret=max(ret,maxlen[b][0]); 101 return (ret); 102 } 103 104 105 void init() 106 { 107 scanf("%d%d%d",&n,&m,&k); 108 for (int i=1;i<=m;i++) 109 scanf("%d%d%d",&edge[i].u,&edge[i].v,&edge[i].w); 110 for (int i=1;i<=n;i++) u[i]=i,h[i]=1; 111 } 112 113 void kruskal() 114 { 115 sort(edge+1,edge+m+1); 116 for (int i=1;i<=m;i++) 117 { 118 int a=edge[i].u,b=edge[i].v; 119 int fa=find(a),fb=find(b); 120 if (fa!=fb) 121 { 122 union_set(fa,fb); 123 addedge(edge[i].u,edge[i].v,edge[i].w); 124 } 125 } 126 } 127 128 void query() 129 { 130 dfs(1,0,1); 131 getanc(); 132 for (int i=0;i<k;i++) 133 { 134 int a,b; 135 scanf("%d%d",&a,&b); 136 printf("%d\n",lca(a,b)); 137 } 138 } 139 140 int main() 141 { 142 init(); 143 kruskal(); 144 query(); 145 return 0; 146 }