题解 CF915F 【Imbalance Value of a Tree】

· · 题解

我们首先显然的套路的\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n} I(i,j)

=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n} \max(i,j)-\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n} \min(i,j)

则我们可以分别求出两部分内容。

假设我们现在是边权,不是点权,那么我们可以使用并查集 \tt{dsu}

具体这么做:

假设我们正在求最大值,我们可以算出每一条边的贡献 =w\times\sum\limits_{i=1}^{n}\sum\limits_{j=i}^{n} f(i,j)

我们考虑从小到大加入每一条边,设当前加入的边是 $(x,y,w)$ ,那么原先加入的每一条边都没有它大,所以我们合并 $x$ 与 $y$ 所在的连通块,**并加入** $w\times s_x\times s_y$ **的贡献**,其中 $s_i$ 表示 $i$ 所在的连通块大小。 为什么呢? 因为在 $x$ 的连通块内任选一个点 $p$ , 在 $y$ 的连通块内任选一个点 $q$ ,则 $p,q$ 之间的**唯一路径一定经过这一条边**,而这一条边是当前全图中最大的。 回到题目,现在我们是点权,所以我们可以**化点为边**,边 $(x,y)$ 的权值 $=\max(w_x,w_y)$ , 其中 $w_i$ 表示 $i$ 点点权。 最小值类似,只不过边权变成两点点权最小值,并且要从大到小加入每一条边。 代码如下: ```cpp #include<cstdio> #include<vector> #include<algorithm> struct edge { int x,y,m1,m2; }; std::vector<int> a[1000005]; int n,fa[1000005],sz[1000005],val[1000005]; long long ans=0; edge f[1000005]; int cmp1(edge x,edge y){return x.m2>y.m2;} int cmp2(edge x,edge y){return x.m1<y.m1;} int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void merge(int x,int y) { int fx=find(x),fy=find(y); fa[fx]=fy;sz[fy]=sz[fy]+sz[fx]; } int main() { scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&val[i]); for (int i=1;i<n;i++) { scanf("%d%d",&f[i].x,&f[i].y); f[i].m1=std::max(val[f[i].x],val[f[i].y]); f[i].m2=std::min(val[f[i].x],val[f[i].y]); } std::sort(f+1,f+n,cmp1); for (int i=1;i<=n;i++) fa[i]=i,sz[i]=1; for (int i=1;i<n;i++) { int x=f[i].x,y=f[i].y; ans=ans-1ll*f[i].m2*sz[find(x)]*sz[find(y)]; merge(x,y); } std::sort(f+1,f+n,cmp2); for (int i=1;i<=n;i++) fa[i]=i,sz[i]=1; for (int i=1;i<n;i++) { int x=f[i].x,y=f[i].y; ans=ans+1ll*f[i].m1*sz[find(x)]*sz[find(y)]; merge(x,y); } printf("%lld\n",ans); return 0; } ``` 然后就可以通过这一道题目了! upd on 2020.8.10 修改了一些错误 upd on 2021.7.28 修改了一些错误,感谢 [U367991](https://www.luogu.com.cn/user/367991)