题意
给出 N N N个点,它们之间有 N − 1 N-1 N−1条路径相连,其中 K K K个特殊点,我们要删去一些边使得这 K K K个点不连通,求最少的删除代价。
思路
可以想到构图。我们删边的最小代价等于用总代价减去构图的最大代价,于是我们可以把边从大到小排序来放入并查集里。当加入一条边时,判断两个点是不是特殊点,还有特殊点的集合里的点都要标记成特殊点,代表特殊点连到这个集合的某一个点都会与另一个特殊点连通,就不符题意。
代码
#include<cstdio>
#include<algorithm>
struct node{
int x, y, z;
}e[100001];
int N, K;
long long ans;
int enemy[100001], father[100001];
int cmp(node x, node y) {
return x.z > y.z;
}
int find(int x) {
return x == father[x] ? x : father[x] = find(father[x]);
}
int main() {
scanf("%d %d", &N, &K);
int x;
for (int i = 1; i <= K; i++) {
scanf("%d", &x);
enemy[x] = 1;
}
for (int i = 1; i < N; i++) {
scanf("%d %d %d", &e[i].x, &e[i].y, &e[i].z);
ans += e[i].z;
father[i] = i;
}
father[N] = N;
std::sort(e + 1, e + N, cmp);
for (int i = 1; i < N; i++) {
int f1 = find(e[i].x), f2 = find(e[i].y);
if (enemy[f1] && enemy[f2]) continue;//特殊点之间不能连通
father[f1] = f2;
ans -= e[i].z;
if (enemy[f1]) enemy[f2] = 1;//标记
else if (enemy[f2]) enemy[f1] = 1;
}
printf("%lld", ans);
}