Forsaken喜欢独一无二的树

/*
题意,删除边使得图在进行最小生成树时,最小生成树唯一
当多个边的权值相同且多条边分别相连的两个点集(树)相同,则认为两条边等价,只保留其中一条
考虑到权值大小连续,从第i条边向后遍历,若
ff(li[i].u)==ff(li[l].u)&&ff(li[i].v)==ff(li[l].v)
或
ff(li[i].u)==ff(li[l].v)&&ff(li[i].v)==ff(li[l].u)
成立时,则说明两条边等价,答案添加边l的边权并继续向后遍历直到边权与i不同,随后再合并两个子树。
*/

#include <bits/stdc++.h>
#define ll long long
#define pii pair<int, int>
using namespace std;
struct lin {
    int u;
    int v;
    ll val;
    bool used;
} li[500001];
int fa[300001];
bool cmp(lin a, lin b) {
    return a.val < b.val;
}
int ff(int x) {
    if (fa[x] == 0)
        fa[x] = x;
    if (fa[x] == x)
        return x;
    return fa[x] = ff(fa[x]);
}
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++) {
        int u, v, val;
        scanf("%d%d%d", &u, &v, &val);
        li[i].u = u;
        li[i].v = v;
        li[i].val = val;
    }
    sort(li + 1, li + 1 + m, cmp);
    ll ans = 0;
    int cnt = 0;
    set<ll> st;
    for (int i = 1; i <= m; i++) {
        int u = li[i].u;
        int v = li[i].v;
        ll val = li[i].val;
        if (ff(u)==ff(v)){
            continue;
        }
        int l = i + 1;
        while(li[l].val==li[i].val){
            if(((ff(li[l].u)==ff(u)&&ff(li[l].v)==ff(v))||(ff(li[l].v)==ff(u)&&ff(li[l].u)==ff(v)))){
                ans += li[l].val;
            }
            l++;
        }
        st.insert(val);
        li[i].used = 1;
        fa[ff(v)] = ff(u);
        cnt++;
    }
    printf("%lld", ans);
}
//https://ac.nowcoder.com/acm/contest/26077/1009

点赞

发表回复