逐个击破

题目链接:逐个击破


正难则反。(其实正面虚树上面dp也可以)

最小的删边,其实就是最大的留边。最后用总和减去最大的留边就是答案。

首先对边排序。从大到小排序。

如果这两个点都是敌人,那么不连边。否则连边。如果有一个敌人,有一个我方,那么连边之后,对于这个联通块就不能再连敌人了。所以再标记根。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,k,f[N],vis[N];	long long res;
struct node{int u,v,w;}t[N];
int cmp(node a,node b){return a.w>b.w;}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++)	f[i]=i;
	for(int i=1,x;i<=k;i++)	scanf("%d",&x),vis[x]=1;
	for(int i=1;i<n;i++)	scanf("%d %d %d",&t[i].u,&t[i].v,&t[i].w),res+=t[i].w;
	sort(t+1,t+n,cmp);
	for(int i=1;i<n;i++){
		int x=find(t[i].u),y=find(t[i].v);
		if(x==y||vis[x]&&vis[y])	continue;
		res-=t[i].w; f[x]=y; vis[y]|=vis[x];
	}
	cout<<res;
	return 0;
}
发布了579 篇原创文章 · 获赞 242 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104310559