【並查集】洛谷_2700 逐個擊破(平津戰役)
阿新 • • 發佈:2018-12-31
題意
給出個點,它們之間有條路徑相連,其中個特殊點,我們要刪去一些邊使得這個點不連通,求最少的刪除代價。
思路
可以想到構圖。我們刪邊的最小代價等於用總代價減去構圖的最大代價,於是我們可以把邊從大到小排序來放入並查集裡。當加入一條邊時,判斷兩個點是不是特殊點,還有特殊點的集合裡的點都要標記成特殊點,代表特殊點連到這個集合的某一個點都會與另一個特殊點連通,就不符題意。
程式碼
#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);
}