abc214 D - Sum of Maximum Weights

题目链接

abc214 D - Sum of Maximum Weights rating : 1341

题目描述

We have a tree with N N N vertices numbered 1 , 2 , … , N 1,2,…,N 1,2,,N.

The i-th edge ( 1 ≤ i ≤ N − 1 1≤i≤N−1 1iN1) connects Vertex u i u_i ui and Vertex v i v_i vi​ and has a weight w i w_i wi .

For different vertices u u u and v v v, let f ( u , v ) f(u,v) f(u,v) be the greatest weight of an edge contained in the shortest path from Vertex u u u to Vertex v v v.

Find ∑ i = 1 N − 1 ∑ j = i + 1 N f ( i , j ) \sum_{i = 1}^{N - 1}\sum_{j = i + 1}^{N} f(i,j) i=1N1j=i+1Nf(i,j)

Constraints

  • 2 ≤ N ≤ 1 0 5 2≤N≤10^5 2N105

  • 1 ≤ u i , v i ≤ N 1≤u_i ,v_i ≤N 1ui,viN

  • 1 ≤ w i ≤ 1 0 7 1≤w_i ≤10^7 1wi107

  • The given graph is a tree.

  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
u1 v1 w1
​⋮
uN−1 vN−1 wN−1

Output

Print the answer.

Sample Input 1

3
1 2 10
2 3 20

Sample Output 1

50

We have f ( 1 , 2 ) = 10 f(1,2)=10 f(1,2)=10, f ( 2 , 3 ) = 20 f(2,3)=20 f(2,3)=20, and f ( 1 , 3 ) = 20 f(1,3)=20 f(1,3)=20, so we should print their sum, or 50 50 50.

Sample Input 2

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

Sample Output 2

76

解法:并查集

题目的大致意思是:给你一颗树,树中每两个相邻节点 u u u v v v 之间的权重是 w w w,并且定义了一种操作 f ( i , j ) f(i,j) f(i,j) 表示节点 i i i 到 节点 j j j 的最短路径上的最大的那个权重值

我们要做的就是求出所有这样的 f ( i , j ) f(i,j) f(i,j) 的总和。

对于本题,我们使用并查集求解。

我们首先对输入 { u , v , w } \{u,v,w\} {u,v,w} 按照权重 w w w 从小到大的排序。

我们从小的权重值 w w w 开始枚举,计算以 w w w 为最大权重值的路径的条数 t t t。这个条数 t = t = t= u u u 所在的连通块元素个数 × \times × v v v 所在的连通块元素个数

我们用一个 s z sz sz 数组来记录每个连通块的元素个数。

对于 u u u v v v,他们的父节点分别是 f i n d ( u ) , f i n d ( v ) find(u) , find(v) find(u),find(v),我们令其为 x , y x,y x,y

  • 如果此时 x = y x = y x=y,说明 u u u v v v 此时就已经在同一个连通块内了,我们就不用计算了。

  • 如果此时 x ≠ y x \neq y x=y,那么我们就要将 x x x y y y 这两个连通块 通过 { u , v , w } \{ u,v,w\} {u,v,w} 这条边连接起来。那么此时 t = s z [ x ] × s z [ y ] t = sz[x] \times sz[y] t=sz[x]×sz[y],所以这条边的贡献就为 t × w = s z [ x ] × s z [ y ] × w t \times w = sz[x] \times sz[y] \times w t×w=sz[x]×sz[y]×w。接着合并这两个连通块, f [ x ] = y , s z [ y ] = s z [ y ] + s z [ x ] f[x] = y , sz[y] =sz[y] + sz[x] f[x]=y,sz[y]=sz[y]+sz[x]这一步操作相当于将 x x x 所代表的连通块作为一个新节点插入到了 以 y y y 代表的连通块中

时间复杂度: O ( n × l o g n ) O(n \times logn) O(n×logn)

C++代码:

#include 
#include 
#include 
#include 
#include 

using namespace std;

using LL = long long;

const int N = 1e5 + 10;
int f[N],sz[N];

int n;

int find(int x){
    if(f[x] != x) {
        return f[x] = find(f[x]);
    }
    else return x;
}

void merge(int x,int y){
    int px = find(x) , py = find(y);
    if(px == py) return;
    f[px] = py;
    sz[py] += sz[px];
}

void solve(){
    cin>>n;
    for(int i = 0;i < n;i++) {
        f[i] = i;
        sz[i] = 1;
    }



    vector<tuple<int,int,int>> a;

    for(int i = 0;i < n - 1;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        --u , --v;
        a.emplace_back(w,u,v);
    }

    sort(a.begin(),a.end());

    LL ans = 0;

    for(auto &[w,u,v]:a){
        int x = find(u) , y = find(v);
        ans += w * 1LL * sz[x] * sz[y]; //将乘积转成 long long 防止溢出
        merge(u,v);
    }

    cout<<ans<<'\n';
}

int main(){

#ifndef ONLINE_JUDGE

    freopen("in.txt","rt",stdin);
    freopen("out.txt","wt",stdout);

#endif


    int t = 1;
    //cin>>t;

    while(t--){
        solve();
    }

    return 0;
}

你可能感兴趣的:(AtCoder,并查集,树)