1. 程式人生 > 其它 >ABC214 D - Sum of Maximum Weights(並查集+圖論)

ABC214 D - Sum of Maximum Weights(並查集+圖論)

目錄

Description

有一棵樹,計算 \(\sum_{i=1}^{n-1}\sum_{j=i+1}^{n}f(i,j)\), 其中 \(f(i,j)\) 代表 \(i,j\) 兩個節點之間最短路徑上的最大邊權

State

\(1<=n<=10^{5}\)

\(1<=u,v<=n\)

\(1<=w<=10^7\)

Input

5
1 2 1
2 3 2
4 2 5
3 5 14

Output

76

Solution

題目屬於貢獻題,即每條邊對答案的貢獻是是多少

看一下樣例中的 \(2,4\) 這條邊,邊權 \(x=5\) 對答案的貢獻為 \(3x\) ,不難發現,較大的邊權會將較小的邊權覆蓋,所以按照邊權順序來;

一條邊左右兩個端點各形成兩棵樹,而且邊權一定小,所以這兩棵樹的大小相乘便是這條邊的貢獻

Code

const int N = 2e5 + 5;

    ll n, m, _;
    int i, j, k;
    tuple<int, int ,int> a[N];
    int fa[N];
    int sz[N];

int Find(int x)
{
    if(x == fa[x]) return x;
    else return fa[x] = Find(fa[x]);
}

void Union(int x, int y)
{
    int nx = Find(x), ny = Find(y);
    if(nx != ny){
        fa[nx] = ny;
        sz[ny] += sz[nx];
    }
    return void();
}

signed main()
{
    //IOS;
    while(~ sd(n)){
        rep(i, 1, n){
            fa[i] = i;
            sz[i] = 1;
        }
        rep(i, 1, n - 1){
            sddd(get<1>(a[i]), get<2>(a[i]), get<0>(a[i]));
        }
        sort(a + 1, a + 1 + n);
        ll ans = 0;
        rep(i, 1, n){
            int x = Find(get<1>(a[i])), y = Find(get<2>(a[i]));
            ans += (ll)sz[x] * sz[y] * get<0>(a[i]);
            Union(x, y);
        }
        pll(ans);
    }
    //PAUSE;
    return 0;
}