AT_abc348_e 的题解

(一)

感觉 D>E。

考虑换根DP,把节点 1 当作一开始的根节点。

先搜一遍,把 f(1) 算出。

当将计算的节点从父结点往子节点转移时,每个节点到计算的节点的距离要么 1 要么 +1,取决于是否在子节点的子树内。

可以提前处理字数内 C 的值的和,来计算 f 的变化量。

(二)

注意:这题答案可能非常大, min 一开始要设为 1020

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mxn=1e6+10;
int n,head[mxn],cnt,dep[mxn],sum,dp[mxn],s[mxn],c[mxn];
struct node{
	int to,nxt;
}edge[mxn<<1];
void add(int u,int v){
	edge[++cnt]=(node){v,head[u]};
	head[u]=cnt;
}
void dfs(int u,int fa){
	dep[u]=dep[fa]+1ll;
	s[u]=c[u];
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==fa)continue;
		dfs(v,u);
		s[u]+=s[v];
	}
}
void dfs2(int u,int fa){
	for(int i=head[u];i;i=edge[i].nxt){
		int v=edge[i].to;
		if(v==fa)continue;
		dp[v]=dp[u]-s[v]+(sum-s[v]);
		dfs2(v,u);
	}
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%lld%lld",&u,&v);
		add(u,v),add(v,u);
	}
	for(int i=1;i<=n;i++)scanf("%lld",&c[i]),sum+=c[i];
	dfs(1,0);
	for(int i=1;i<=n;i++)dp[1]+=(dep[i]-1ll)*c[i];
	dfs2(1,0);
	int ans=1e20;
	for(int i=1;i<=n;i++)ans=min(ans,dp[i]);
	printf("%lld",ans);
	return 0;
}
posted @   Jerry_heng  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示