Forsaken喜歡獨一無二的樹

題意描述

題目連接
node

開始想法:

開始的想法是圖中一個環內,若是最大的兩條邊相同,那麼就應該刪除其中一條;作法是:
(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;
}
相關文章
相關標籤/搜索