codeforces-915F Imbalance Value of a Tree(并查集+树上统计)

链接:http://codeforces.com/problemset/problem/915/F
题意:树上每一个点有一个点权,求树上所有的路径的(最大点权值-最小点权值)之和

题解:可以考虑先求出所有路径中最大点权值之和。显然,每一个点都能对一些路径产生贡献,我们可以先按点权从小到大排序,然后每次取一个点,那么所取的点就是在当前已取出的点中最大的。用并查集维护之前取出的在不同子树中的点以及数量,并两两相乘,更新当前点的贡献。这一步有点像之前的一道单调栈的题目,求区间的数目,这些区间中的最大值是某个点,大概就是用该点左边能扩展的长度乘上右边扩展的长度。这也是这一类树上统计的方法。

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;

int n;
vector<int> G[1000010];

struct node{
    long long w;
    int id;
}p[1000010];

bool cmp(node a, node b){
    return a.w<b.w;
}
long long res;

int fa[1000010];
int vis[1000010];
int num[1000010]; //以x为根的子树的节点个数
int Find(int x){
    return fa[x] == x ? x:(fa[x]=Find(fa[x]));
}

void solve(){
    for(int i = 1; i<=n; i++){
        fa[i] = i;
        num[i] = 1;
        vis[i] = 0;
    }
    sort(p+1, p+1+n, cmp);
    for(int i = 1; i<=n; i++){
        for(int j = 0; j<G[p[i].id].size(); j++){
            int v = G[p[i].id][j];
            int temp = Find(v);
            if(!vis[temp]) continue; //注意是要找已经访问过的
            res+=(long long)p[i].w*num[temp]*num[p[i].id];
            fa[temp] = p[i].id;
            num[p[i].id]+=num[temp];
        }
        vis[p[i].id] = 1;
        p[i].w = -p[i].w;
    }
    //cout<<res<<endl;
}


int main(){
    cin>>n;
    for(int i = 1; i<=n; i++){
        p[i].id = i;
       scanf("%I64d", &p[i].w);
    }
    for(int i = 1; i<n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    res = 0;
    solve();
    //cout<<res<<endl;
    solve();
    printf("%I64d\n", res);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值