Forsaken喜欢独一无二的树

题意描述

题目链接

开始想法:

开始的想法是图中一个环内,如果最大的两条边相同,那么就应该删除其中一条;做法是:
(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;
}

猜你喜欢

转载自www.cnblogs.com/xidian-mao/p/11761160.html