(一)
感觉 D>E。
考虑换根DP,把节点 \(1\) 当作一开始的根节点。
先搜一遍,把 \(f(1)\) 算出。
当将计算的节点从父结点往子节点转移时,每个节点到计算的节点的距离要么 \(-1\) 要么 \(+1\),取决于是否在子节点的子树内。
可以提前处理字数内 \(C\) 的值的和,来计算 \(f\) 的变化量。
(二)
注意:这题答案可能非常大, \(min\) 一开始要设为 \(10^{20}\)。
#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;
}
标签:int,题解,long,mxn,abc348,节点
From: https://www.cnblogs.com/Jh763878/p/18122335