「bsoj5042」论战大原题 - Kruskal重构树 | Bill Yang's Blog

「bsoj5042」论战大原题 - Kruskal重构树

题目大意

给定一个n个点m条边的无向图,定义一条路径的长度为路径上最小边的权值。
定义dist(i,j)为起点为i,终点为j的长度最长的路径的长度。求出第k大的dist(i,j)(i\<j)。


题目分析

这道题似乎可以直接Kruskal的时候处理一下即可。
但是我比较喜欢Kruskal重构树。
关于Kruskal重构树可以看看这里

我们可以从大到小加边,然后统计该边对答案的贡献。
显然只可能有其合并的两个集合size+1乘起来条路径经过该边,因为从大到小加边,所以路径上最小边一定是该边。

重复以上过程,即可得出答案。


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=400005;
struct Edge {
int from,to;
LL dist;
bool operator < (const Edge& b) const {
return dist>b.dist;
}
} edge[maxn];
LL n,New,m,k,father[maxn],Size[maxn],Toans[maxn],Val[maxn],tot=0;
int Get_Father(int x) {
if(father[x]==x)return x;
return father[x]=Get_Father(father[x]);
}
void Kruskal() {
sort(edge+1,edge+m+1);
for(int i=1; i<=2*n; i++)father[i]=i;
int cnt=0;
for(int i=1; i<=m; i++) {
int fx=Get_Father(edge[i].from),fy=Get_Father(edge[i].to);
if(fx!=fy) {
father[fx]=father[fy]=++New;
Size[New]=Size[fx]+Size[fy]+1;
Toans[New]=(Size[fx]+1)*(Size[fy]+1);
Val[New]=edge[i].dist;
tot+=Toans[New];
if(tot>=k) {
printf("%lld\n",Val[New]);
return;
}
cnt++;
if(cnt==n-1)break;
}
}
}
int main() {
New=n=Get_Int();
m=Get_Int();
k=Get_Int();
for(int i=1; i<=m; i++) {
int x=Get_Int(),y=Get_Int();
LL v=Get_Int();
edge[i]=(Edge) {x,y,v};
}
Kruskal();
return 0;
}
本篇文章有用吗?有用还不快点击!
0%