[LUOGU 2700] 逐个击破 {并查集}

版权声明:请大家斧正,如喜欢的话,为拙见点一个赞吧。 https://blog.csdn.net/qq_39897867/article/details/83214886

文章目录

题目

https://www.luogu.org/problemnew/show/P2700


解题思路

这道题可以逆向思考,把断边变成建边。要求删掉最少的边,那肯定是构较大的边,先从大到小排一个序,再用并查集判断一下两点是否同一联通块。


代码

#include<cstdio>
#include<algorithm>
#define rr register 
using namespace std; 
struct node{int x,y,z;}a[100010];
int n,k,f[100010];
long long ans; 
bool b[100010];  
bool cmp(node x,node y){return x.z>y.z; }
inline int found(int x) { return f[x]==x?f[x]:f[x]=found(f[x]);}
inline int read()
{
	int p=0,f=1; char c=getchar(); 
	while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
	while (c>='0'&&c<='9') p=(p<<3)+(p<<1)+c-'0',c=getchar(); 
	return p*f; 
}
int main()
{
	n=read(); k=read(); f[n]=n; 
	for (rr int i=1;i<=k;i++) b[read()]=true; 
	for (rr int i=1;i<n;f[i]=i,i++) 
		a[i]=(node){read(),read(),read()},ans+=(long long)a[i].z; 
	sort(a+1,a+n,cmp); 
	for (rr int i=1;i<n;i++)
	{
		int x=found(a[i].x),y=found(a[i].y),z=a[i].z; 
		if (b[x]&&b[y]) continue; 
		f[x]=f[y]; ans-=(long long)z; 
		if (b[x]) b[y]=true; 
		else if (b[y]) b[x]=true; 
	}
	printf("%lld",ans); 
}

猜你喜欢

转载自blog.csdn.net/qq_39897867/article/details/83214886