BZOJ 3732: Network 最小生成树 倍增
3732: Network
题目连接:
http://www.lydsy.com/JudgeOnline/problem.php?id=3732
Description
给你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点的所有路径中,最长的边最小值是多少?
Input
第一行: N, M, K。
第2..M+1行: 三个正整数:X, Y, and D (1 <= X <=N; 1 <= Y <= N). 表示X与Y之间有一条长度为D的边。
第M+2..M+K+1行: 每行两个整数A B,表示询问从A点走到B点的所有路径中,最长的边最小值是多少?
Output
对每个询问,输出最长的边最小值是多少。
Sample Input
6 6 8
1 2 5
2 3 4
3 4 3
1 4 8
2 5 7
4 6 2
1 2
1 3
1 4
2 3
2 4
5 1
6 2
6 1
Sample Output
5
5
5
4
4
7
4
5
Hint
1 <= N <= 15,000
1 <= M <= 30,000
1 <= d_j <= 1,000,000,000
1 <= K <= 15,000
题意
题解:
我一开始竟然在想一个好傻的问题:生成一棵最长边最小的树,可不可以保证任意两点之间最长边最小。(最小生成树没学好的结果)
这题比较裸,先生成最小生成树,然后倍增求两点路径最长边。
当然树链剖分也行,感觉树剖也挺容易打的。
Debug
1.n,m混用,导致最小生成树写错了。
2.数组开小了,点和边应该分开开数组。
3.倍增时,如果调整高度相同时,如果x==y,要直接返回答案。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define N 40050 5 int n,m,dp[N],mx[N][15],fu[N][15],mm[N]; 6 int tot,last[N]; 7 struct Edge 8 { 9 int from,to,val,s; 10 bool operator <(const Edge&b)const 11 {return val<b.val;} 12 }a[N],edges[N<<1]; 13 template<typename T>void read(T&x) 14 { 15 ll k=0; char c=getchar(); 16 x=0; 17 while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar(); 18 if (c==EOF)exit(0); 19 while(isdigit(c))x=x*10+c-'0',c=getchar(); 20 x=k?-x:x; 21 } 22 void read_char(char &c) 23 {while(!isalpha(c=getchar())&&c!=EOF);} 24 void AddEdge(int x,int y,int z) 25 { 26 edges[++tot]=Edge{x,y,z,last[x]}; 27 last[x]=tot; 28 } 29 int gf(int x,int *fa) 30 { 31 if(x==fa[x])return x; 32 return fa[x]=gf(fa[x],fa); 33 } 34 void MST(Edge *edges) 35 { 36 static Edge a[N]; 37 static int fa[N]; 38 for(int i=1;i<=m;i++)a[i]=edges[i]; 39 for(int i=1;i<=n;i++)fa[i]=i;// 40 sort(a+1,a+m+1); 41 int num=0; 42 for(int i=1;i<=m;i++)// 43 { 44 int fx=gf(a[i].from,fa),fy=gf(a[i].to,fa); 45 if (fx==fy)continue; 46 AddEdge(a[i].from,a[i].to,a[i].val); 47 AddEdge(a[i].to,a[i].from,a[i].val); 48 fa[fx]=fy; 49 if (++num==n-1)break; 50 } 51 } 52 void dfs(int x,int pre) 53 { 54 fu[x][0]=pre; 55 dp[x]=dp[pre]+1; 56 for(int i=last[x];i;i=edges[i].s) 57 { 58 Edge &e=edges[i]; 59 if (e.to==pre)continue; 60 mx[e.to][0]=e.val; 61 dfs(e.to,x); 62 } 63 } 64 void init_ST() 65 { 66 for(int i=2;i<=n;i++)mm[i]=mm[i>>1]+1; 67 for(int i=1;i<=14;i++) 68 for(int j=1;j<=n;j++)// 69 { 70 fu[j][i]=fu[fu[j][i-1]][i-1]; 71 mx[j][i]=max(mx[j][i-1],mx[fu[j][i-1]][i-1]); 72 } 73 } 74 int GetLca(int x,int y) 75 { 76 int ans=0; 77 if (dp[x]<dp[y])swap(x,y); 78 int k=mm[dp[x]-dp[y]];// 79 for(int i=k;i>=0;i--) 80 if (dp[fu[x][i]]>=dp[y]) 81 { 82 ans=max(ans,mx[x][i]); 83 x=fu[x][i]; 84 } 85 if (x==y)return ans;// 86 k=mm[dp[x]-1]; 87 for(int i=k;i>=0;i--) 88 if (fu[x][i]!=fu[y][i]) 89 { 90 ans=max(ans,mx[x][i]); 91 ans=max(ans,mx[y][i]); 92 x=fu[x][i]; 93 y=fu[y][i]; 94 } 95 ans=max(ans,mx[x][0]); 96 ans=max(ans,mx[y][0]); 97 return ans; 98 } 99 int main() 100 { 101 #ifndef ONLINE_JUDGE 102 freopen("aa.in","r",stdin); 103 #endif 104 int q; 105 read(n); read(m); read(q); 106 for(int i=1;i<=m;i++) 107 { 108 int x,y,z; 109 read(x); read(y); read(z); 110 a[i]=Edge{x,y,z,0}; 111 } 112 MST(a); 113 dfs(1,0); 114 init_ST(); 115 for(int i=1;i<=q;i++) 116 { 117 int x,y; 118 read(x); read(y); 119 printf("%d\n",GetLca(x,y)); 120 } 121 }