【并查集】洛谷_2700 逐个击破(平津战役)

题意

给出 N N N个点,它们之间有 N − 1 N-1 N1条路径相连,其中 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值