ABC348E Minimize Sum of Distances 题解

ABC348E Minimize Sum of Distances

题目大意

给定一棵共 \(n\) 个节点的树, 第 \(i\) 个点的权重为 \(c_i\)。定义 \(f(x)\) 表示树上所有点到节点 \(x\) 的距离乘上权重,即 \(f(x)=\sum\limits_{i=1}^n(c_i\times dis(x, i))\)。求 \(\min\limits_{u=1}^nf(u)\)

Solve

一眼换根。

考虑先以节点 \(1\) 为根,则 \(f(1)=\sum\limits_{i=1}^n(c_i\times d_i)\),(\(d_i\) 表示 \(i\) 的深度)。然后考虑换根求 \(f(u),u\in[2,n]\)

image-20240409193224147

如图,以 \(u=2\) 时为例。记 \(sum_u\) 为当以 \(1\) 为根时 \(u\) 的子树内的点的权值和。当根从 \(fa_2=1\) 转移至 \(2\) 时,对于在 \(2\) 的子树里的节点,他们的深度都减少了 \(1\),那么 \(\sum\limits_{i\in son_2}(c_i\times d_i)\) 就总共减少了 \(sum_u\);对于不在 \(2\) 的子树里的点,他们的深度都增加了 \(1\),共增加 \(sum_1-sum_u\)。整理一下并推广至所有 \(u\in [2,n]\),有: \(f(u)=f(fa_u)-sum_u+sum_1-sum_u\)

Code

#include<bits/stdc++.h>
#pragma GCC optimize(1,2,3,"Ofast","inline")
using namespace std;
#define int long long
inline int read()
{
	short f=1;
	int x=0;
	char c=getchar();
	while(c<'0'||c>'9')	{if(c=='-')	f=-1;c=getchar();}
	while(c>='0'&&c<='9')	x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,a,b,c[100010],f[100010],ans;
vector<int>e[100010];
void dfs(int u,int fa,int d)
{
	f[1]+=d*c[u];
	for(auto i:e[u])
		if(i!=fa)	dfs(i,u,-~d),c[u]+=c[i];
}
void dp(int u,int fa)
{
	for(auto i:e[u])
		if(i!=fa)	f[i]=f[u]-c[i]+c[1]-c[i],dp(i,u);
}
signed main()
{
	n=read();
	for(int i=1;i<n;i=-~i)
		a=read(),b=read(),
		e[a].push_back(b),e[b].push_back(a);
	for(int i=1;i<=n;i=-~i)	c[i]=read();
	dfs(1,0,0);ans=f[1];dp(1,0);
	for(int i=1;i<=n;i=-~i)	ans=min(ans,f[i]);
	return printf("%lld",ans),0;
}
posted @ 2024-06-13 19:41  Sorato  阅读(87)  评论(0)    收藏  举报