[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

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

转载自http://www.cnblogs.com/ZegWe/p/6243883.html

我们按照kruskal求最小生成树的方式加边,但每次在加边时,新建一个节点,然后把两个联通块(其实是两棵二叉树)的根节点作为其左右儿子,把边权赋值给新建节点。那么我们可以发现这棵树有几个性质。

  1. 是一棵二叉树(虽然这道题并没有什么卵用);
  2. 满足父节点的值大于等于儿子节点,是一个大顶堆,这是最关键的一点;
  3. 原图上任意两点间路径最长边的最小值等于其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 }

 

posted @ 2017-10-09 16:44  Z-Y-Y-S  阅读(253)  评论(0编辑  收藏  举报