题意描述

题目链接

开始想法:

开始的想法是图中一个环内,如果最大的两条边相同,那么就应该删除其中一条;做法是:
(1)将边从小到大排序,之后并查集合并x,y;
(2)用p[fx]维护并查集最大的边;
(3)如果fx==fy且当前边权值w==p[fx],说明应该删除这条边
这个想法是错误,这个在并查集上最大的边不一定在环上

核心:

看了别人是这样做的
(1)将边从大到小排序
(2)对于相同权值的边统一考虑,若这条边上两点不连通开始全部加入ans中;然后在考虑重复加入的情况,也是逐渐加入这些权值相同的边,若两点不连通ans-=w; 否则说明这条边不唯一,应该删去

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+7;
struct node{
	int x,y;
	int w;
	bool operator<(const node& a) const {
		return w<a.w;
	}
};
node e[N];
int fa[N];
int n,m;
LL ans=0;
int find_fa(int x) {
	if(fa[x]!=x)
		fa[x]=find_fa(fa[x]);
	return fa[x];
}
int main()
{
	scanf("%d %d",&n,&m);
	for(int i=1;i<=m;i++)	scanf("%d %d %d",&e[i].x,&e[i].y,&e[i].w);
	for(int i=1;i<=n;i++)	fa[i]=i;
	sort(e+1,e+1+m);
	for(int i=1;i<=m;) {
		int w=e[i].w;
		int j=i;
		while(j<=m&&e[j].w==w) j++;
		for (int k=i;k<j;k++) {
			int fx=find_fa(e[k].x);
			int fy=find_fa(e[k].y);
			if(fx!=fy)
				ans+=w;
		}
		for (int k=i;k<j;k++) {
			int fx=find_fa(e[k].x);
			int fy=find_fa(e[k].y);
			if(fx!=fy) {
				fa[fx]=fy;
				ans-=w;
			}
		}
		i=j;
	}
	printf("%lld\n",ans);
	return 0;
}