[BZOJ 3732]Network
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 < = 20,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
转载自http://www.cnblogs.com/ZegWe/p/6243883.html
我们按照kruskal求最小生成树的方式加边,但每次在加边时,新建一个节点,然后把两个联通块(其实是两棵二叉树)的根节点作为其左右儿子,把边权赋值给新建节点。那么我们可以发现这棵树有几个性质。
- 是一棵二叉树(虽然这道题并没有什么卵用);
- 满足父节点的值大于等于儿子节点,是一个大顶堆,这是最关键的一点;
- 原图上任意两点间路径最长边的最小值等于其lca的值;
这种建树的方法称作kruskal重构树。
那么A,B的lca就是所求答案。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #define link LL 6 using namespace std; 7 struct Link 8 { 9 int u,v,c; 10 }link[100001]; 11 bool cmp(Link a,Link b) 12 { 13 return a.c<b.c; 14 } 15 struct Node 16 { 17 int next,to; 18 }edge[600001]; 19 int head[100001],num,fa[100001][18],dep[100001],n,m,k,pos,cnt; 20 int set[100001],c[100001]; 21 void add(int u,int v) 22 { 23 num++; 24 edge[num].next=head[u]; 25 head[u]=num; 26 edge[num].to=v; 27 } 28 void dfs(int x,int pa) 29 {int i; 30 dep[x]=dep[pa]+1; 31 for (i=1;i<=17;i++) 32 fa[x][i]=fa[fa[x][i-1]][i-1]; 33 for (i=head[x];i;i=edge[i].next) 34 { 35 int v=edge[i].to; 36 if (v!=pa) 37 { 38 fa[v][0]=x; 39 dfs(v,x); 40 } 41 } 42 } 43 int LCA(int x,int y) 44 {int i; 45 if (dep[x]<dep[y]) swap(x,y); 46 for (i=17;i>=0;i--) 47 if ((1<<i)<=dep[x]-dep[y]) x=fa[x][i]; 48 if (x==y) return x; 49 for (i=17;i>=0;i--) 50 { 51 if (fa[x][i]!=fa[y][i]) 52 { 53 x=fa[x][i]; 54 y=fa[y][i]; 55 } 56 } 57 x=fa[x][0];y=fa[y][0]; 58 return x; 59 } 60 int find(int x) 61 { 62 if (set[x]!=0) set[x]=find(set[x]); 63 if (set[x]==0) return x; 64 else return set[x]; 65 } 66 int main() 67 {int i,x,y; 68 cin>>n>>m>>k; 69 for (i=1;i<=m;i++) 70 { 71 scanf("%d%d%d",&link[i].u,&link[i].v,&link[i].c); 72 } 73 sort(link+1,link+m+1,cmp); 74 pos=n;cnt=0; 75 for (i=1;i<=m;i++) 76 { 77 int p=find(link[i].u); 78 int q=find(link[i].v); 79 if (p!=q) 80 { 81 c[++pos]=link[i].c; 82 add(p,pos); 83 add(pos,p); 84 add(q,pos); 85 add(pos,q); 86 set[p]=set[q]=pos; 87 ++cnt; 88 if (cnt==n-1) break; 89 } 90 } 91 dfs(pos,0); 92 while (k--) 93 { 94 scanf("%d%d",&x,&y); 95 printf("%d\n",c[LCA(x,y)]); 96 } 97 }