题意描述
题目链接
开始想法:
开始的想法是图中一个环内,如果最大的两条边相同,那么就应该删除其中一条;做法是:
(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
",ans);
return 0;
}