旅游 \operatorname{旅游} 旅游
题目链接: SSL比赛 1486 \operatorname{SSL比赛\ 1486} SSL比赛 1486
题目
输入
输出
样例输入
1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000
样例输出
2
6
12
数据范围
思路
这道题其实是一道并查集。
我们就把所有的边按边权从小到大排序,然后一条一条看,如果两边不连通,就相连,一边到另外一边的最大人气就是这条边的人气。
(挺像最小生成树的,我觉得)
那怎么看答案呢?
设
a
n
s
[
i
]
ans[i]
ans[i] 为最大容忍限度为
i
i
i 的时候答案是多少,再设
n
u
m
[
i
]
num[i]
num[i] 为
i
i
i 所在的集合里面有多少个点。
那我们连边的时候,
n
u
m
num
num 就是两个原来的
n
u
m
num
num 相加,而
a
n
s
[
a
[
i
]
.
c
o
s
t
]
+
=
n
u
m
[
x
]
∗
n
u
m
[
y
]
∗
2
ans[a[i].cost]+=num[x]*num[y]*2
ans[a[i].cost]+=num[x]∗num[y]∗2 。
(
a
[
i
]
.
c
o
s
t
a[i].cost
a[i].cost 就是这条边的人气值,乘
2
2
2 因为
(
x
,
y
)
(x,y)
(x,y) 和
(
y
,
x
)
(y,x)
(y,x) 算两个)
(就是左边任意的点走到右边任意的点加上右边任意的点走到左边任意的点)
然后我们把 a n s ans ans 从前缀和一下,就可以直接读入 x x x 然后输出 a n s [ x ] ans[x] ans[x] 了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int T;
struct node {
int x, y, cost;
}a[200001];
int n, m, q, fa[200001], maxn, ans[200001], num[200001], x;
int read() {//快读
int an = 0, zhengfu = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') zhengfu = -zhengfu;
c = getchar();
}
while (c >= '0' && c <= '9') {
an = an * 10 + c - '0';
c = getchar();
}
return an * zhengfu;
}
bool cmp(node x, node y) {//按边权排序
return x.cost < y.cost;
}
int find(int now) {//并查集
if (fa[now] == now) return now;
return fa[now] = find(fa[now]);
}
void work() {
int X, Y;
for (int i = 1; i <= m; i++) {//枚举边
X = find(a[i].x);
Y = find(a[i].y);
if (X == Y) continue;//看是否连通
fa[X] = Y;
ans[a[i].cost] += num[X] * num[Y] * 2;//求出新答案
num[Y] += num[X];//求出新长度
}
}
int main() {
T = read();//读入
for (int times = 1; times <= T; times++) {
memset(ans, 0, sizeof(ans));//初始化
n = read();//读入
m = read();
q = read();
for (int i = 1; i <= m; i++) {
a[i].x = read();//读入
a[i].y = read();
a[i].cost = read();
maxn = max(maxn, a[i].cost);//记录
}
sort(a + 1, a + m + 1, cmp);//按边权排序
for (int i = 1; i <= n; i++) {//初始化
fa[i] = i;
num[i] = 1;
}
work();
for (int i = 2; i <= maxn; i++)//前缀和
ans[i] += ans[i - 1];
for (int i = 1; i <= q; i++) {
x = read();//读入
printf("%d\n", ans[x]);//输出
}
}
return 0;
}