AtCoder Beginner Contest 214

zhujio / 2023-08-12 / 原文

AtCoder Beginner Contest 214 - AtCoder


 

[ABC214D] Sum of Maximum Weights ------------------------------( 典 )

题意:给出一颗 N - 1 条边的树,求树上任意两点间路径上的最大值的和

这种问题考虑每条边单独看贡献,但是刚开始没太想明白怎么计算贡献,后面看了洛谷题解才懂了

----------------------------------------------------------------------------------------------------------------------------------------

也就是说加入边 s 是一条连通点 a,b 路径上的最大一条边,那么 a,b两点路径上的边一定是小于 s 的权值的

若对所有边权排了个序,s一定是 a 到 b路径上最后一个加入的边,那么此时用一个并查集维护,sz[ a ] 就是在边权小于s的情况下有多少个点是可以到达 a 的,同理sz[ b ]

那么由乘法原理就可以计算出 a 到 b 有多少种方案(sz[ a ] * sz[ b ]),贡献也就算出来了

 

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
typedef long long ll;

const int N = 1e5 + 5;

struct Node{
    int x, y, v;
}a[N];

bool cmp(Node a,Node b){
    return a.v < b.v;
}

int fa[N], sz[N];

int Findset(int x){
    return (x == fa[x]) ? x : fa[x] = Findset(fa[x]);
}

signed main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int n; cin >> n;
    for(int i = 1; i < n; i++){
         cin >> a[i].x >> a[i].y >> a[i].v;
    }
    for(int i = 1; i <= n; i++)fa[i] = i, sz[i] = 1;
    sort(a + 1, a + n, cmp);
    int  ans = 0;
    for(int i = 1; i < n; i++){
        int x = a[i].x, y = a[i].y, v = a[i].v;
        int fx = Findset(x), fy = Findset(y);
        //fx != fy其实是不必要的
        if(fx != fy){
            ans += sz[fx] * sz[fy] * v;
            sz[fx] += sz[fy];
            sz[fy] = 0;
            fa[fy] = fx;
        }
    }
    cout << ans;
    return 0;
}
View Code