题目传送门: http://acm.hdu.edu.cn/showproblem.php?pid=3938
题目的题意有些不清楚,看了discuss才明白。定义图上一条路径的cost为路径中所有边权中最大的那个。对于给定的图,回答当最大的路径长度为l的时候,最多可以有多少顶点对是可及的。
按照Kruskal的思路,按边权从小到大连接顶点,每次相连,如果减少一个连通分量,那么可及顶点对就会增大,增大的个数就是原来两个连通分量顶点个数的乘积,不断累加就可以得到对于不同的l,一共有多少顶点对。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 5e4 + 5;
const int N = 1e4 + 5;
int father[N], sum[N], ans[N];
int n, m, t;
struct edge {
int u, v, w;
} e[M];
struct query {
int id, l;
} q[N];
bool cmp(const edge &e1, const edge &e2)
{
return e1.w < e2.w;
}
bool cmp1(const query &q1, const query &q2)
{
return q1.l < q2.l;
}
int find(int x)
{
while (x != father[x]) {
father[x] = father[father[x]];
x = father[x];
}
return x;
}
int merge(int x, int y)
{
x = find(x);
y = find(y);
if (x != y) {
father[y] = x;
sum[x] += sum[y];
return (sum[x] - sum[y]) * sum[y];
} else return 0;
}
void init(void)
{
for (int i = 1; i <= n; i ++) {
sum[i] = 1;
father[i] = i;
}
}
int main()
{
while (~scanf("%d%d%d", &n, &m, &t)) {
init();
for (int i = 1; i <= m; i ++) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + 1 + m, cmp);
for (int i = 1; i <= t; i ++) {
scanf("%d",&q[i].l);
q[i].id = i;
}
sort(q + 1, q + 1 + t, cmp1);
int cnt = 0, j = 1;
for (int i = 1; i <= t; i ++) {
while (j <= m && e[j].w <= q[i].l) {
cnt += merge(e[j].u, e[j].v);
++ j;
}
ans[q[i].id] = cnt;
}
for (int i = 1; i <= t; i ++) {
printf("%d\n", ans[i]);
}
}
return 0;
}