CF915F Imbalance Value of a Tree

本文介绍了一种解决树形结构中所有点对(i,j)间链上最大点权-最小点权总和问题的算法。通过并查集结合特定技巧,先将边权定义为两端点的最大权值,再按权值从小到大合并连通块,统计每次合并时的size乘积,最终得到目标总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给你一棵树,求所有点对(i,j)之间链上的最大点权-最小点权的总和?

 

标程:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1000005;
 5 struct node{int u,v,w;}e[N];
 6 int a[N],f[N],sz[N],n;
 7 ll ans;
 8 int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
 9 bool operator < (const node &A,const node &B) {return A.w<B.w;}
10 void solve()
11 {
12   for (int i=1;i<=n;i++) f[i]=i,sz[i]=1;
13   for (int i=1;i<n;i++) e[i].w=max(a[e[i].u],a[e[i].v]);
14   sort(e+1,e+n);
15   for (int i=1;i<n;i++)
16   {
17     int x=find(e[i].u),y=find(e[i].v);
18     if (x==y) continue;
19     ans+=(ll)e[i].w*sz[x]*sz[y];
20     f[x]=y;sz[y]+=sz[x];
21   }
22 }
23 int main()
24 {
25    scanf("%d",&n);
26    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
27    for (int i=1;i<n;i++) scanf("%d%d",&e[i].u,&e[i].v);
28    solve();
29    for (int i=1;i<=n;i++) a[i]=-a[i];
30    solve();
31    printf("%lld\n",ans);
32    return 0;
33 }

 

题解:并查集+技巧

一个思路:按照点权从大到小加点,每次连通块分裂,统计该点相连结的两个连通块的size乘积。

但是分裂很难维护。

所有反过来做就是合并了是吧。并查集。

由于点也很难处理,我们定义边权为该边连接的两个端点的较大权值(以求链上最大为例,最大最小是一样的)。从小到大加边,统计该边两个端点所在的连通块size乘积(这两个连通块的点权都<=该边的权值)。然后合并这两个端点。

转载于:https://www.cnblogs.com/Scx117/p/9101697.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值