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
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
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
正解:最小生成树+倍增lca
解题报告:
大概题意是给定一个无向图,然后求两点之间的路径中权值最大的边的最小值
望着这道题10分钟之后感觉做不到一眼秒题,老老实实画图,结果发现我真是太弱了,居然没有发现满足题意的条件竟然是最小生成树的性质。。。
显然先构出最小生成树,其他的边是没有用的,可以删掉。
构出最小生成树之后,就考虑两点间的路径上的最大值。
可以在求lca的时候顺便维护一下就可以了。
我开始打了一个树链剖分+线段树,然而上午脑袋不是很清白,而且鬼畜的BZOJ,居然迷之RE了两次。
好吧,被迫改用倍增,然后就过了,并不知道为什么树链剖分哪里打萎了。
(这道题其实就是NOIP2013的原题货车运输的改版的好吗,几乎一模一样)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<vector> 8 #include<queue> 9 #include<string> 10 #ifdef WIN32 11 #define OT "%I64d" 12 #else 13 #define OT "%lld" 14 #endif 15 using namespace std; 16 typedef long long LL; 17 int n,m; 18 int u[200011],to[200011],w[200011]; 19 int first[200011],next[200011],u1[200011],to1[200011],ww[200011]; 20 int father[200011],height[200011]; 21 int f[100011][16],quan[100011][16]; 22 23 inline int getint(){ 24 int q=0,w=0; 25 char c=getchar(); 26 while(c!='-' && ( c<'0' || c>'9' ) ) c=getchar(); 27 if(c=='-') q=1,c=getchar(); 28 while(c>='0' && c<='9') w=w*10+c-'0',c=getchar(); 29 return q?-w:w; 30 } 31 32 inline void qsort(int l,int r) 33 { 34 int i=l,j=r; 35 int mid=w[(i+j)/2],p; 36 do 37 { 38 while(w[i]<mid)i++; 39 while(w[j]>mid)j--; 40 if(i<=j) 41 { 42 p=w[i];w[i]=w[j];w[j]=p; 43 p=u[i];u[i]=u[j];u[j]=p; 44 p=to[i];to[i]=to[j];to[j]=p; 45 i++; 46 j--; 47 } 48 }while(i<=j); 49 if(i<r)qsort(i,r); 50 if(l<j)qsort(l,j); 51 } 52 53 inline int find(int x){ 54 if(father[x]!=x) father[x]=find(father[x]); 55 return father[x]; 56 } 57 58 inline void hebing(int x,int y){ 59 father[y]=x; 60 } 61 62 inline void dfs(int x,int deep){ 63 height[x]=deep; 64 for(int i=1;i<=15;i++){ 65 f[x][i]=f[ f[x][i-1] ][i-1]; 66 quan[x][i]=max( quan[x][i-1],quan[ f[x][i-1] ][i-1] ); 67 } 68 for(int i=first[x];i;i=next[i]){ 69 if(height[to1[i]]==0) 70 { 71 f[ to1[i] ][0]=x; 72 quan[ to1[i] ][0]=ww[i]; 73 dfs(to1[i],deep+1); 74 } 75 } 76 } 77 78 int lca(int x,int y){ 79 if(height[x]<height[y]) { int t=x;x=y;y=t; } 80 int t=0; 81 while((1<<t) <=height[x]) t++; 82 t--; 83 int ans1=-0x7ffffff,ans2=-0x7ffffff; 84 for(int i=t;i>=0;i--){ 85 if(height[x]-(1<<i)>=height[y]) { 86 ans1=max(ans1,quan[x][i]); 87 x=f[x][i]; 88 } 89 } 90 if(x==y) return ans1; 91 for(int i=t;i>=0;i--){ 92 if(f[x][i]!=f[y][i]){ 93 ans1=max(ans1,quan[x][i]); ans2=max(ans2,quan[y][i]); 94 x=f[x][i];y=f[y][i]; 95 } 96 } 97 int zong1,zong2; 98 zong1=max(ans1,quan[x][0]); 99 zong2=max(ans2,quan[y][0]); 100 return max(zong1,zong2); 101 } 102 103 inline void work(){ 104 qsort(1,m); 105 for(int i=1;i<=n;i++) father[i]=i; 106 int i=1,j=0; 107 int yigong=0; 108 while(i<=m){ 109 int r1=find(u[i]);int r2=find(to[i]); 110 hebing(r1,r2); 111 yigong++; 112 j++; next[j]=first[u[i]]; first[u[i]]=j;ww[j]=w[i]; to1[j]=to[i]; u1[j]=u[i]; 113 j++; next[j]=first[to[i]]; first[to[i]]=j;ww[j]=w[i]; to1[j]=u[i]; u1[j]=to[i]; 114 i++; 115 while(find(u[i])==find(to[i]) && i<=m) 116 i++; 117 } 118 for(int i=1;i<=n;i++) 119 if(father[i]==i) 120 { 121 dfs(i,1); 122 } 123 } 124 125 int main() 126 { 127 n=getint();m=getint();int q=getint(); 128 int ljh,jump,jumpjump; 129 for(int i=1;i<=m;i++){ 130 ljh=getint();jump=getint();jumpjump=getint(); 131 u[i]=ljh;to[i]=jump;w[i]=jumpjump; 132 } 133 134 work(); 135 for(int i=1;i<=q;i++){ 136 ljh=getint();jump=getint(); 137 int ans=lca(ljh,jump); 138 printf("%d ",ans); 139 } 140 return 0; 141 }