我们在树上的每个点iii上放aia_iai个小点,初始时先让每个点单独减,这样要花费aia_iai之和的次数。
然后尝试把某些减合并。一个点上面的小点至多可以向两个相邻的小点连边(这两个小点不能在同一个点上)。每连一条边,合并次数+1,答案-1。
问题变成求一棵树内的最大合并次数。
首先明确该问题满足最优子结构,即考虑以UUU为根的子树时,若U,VU,VU,V上的小点u,vu,vu,v可以合并,合并u,vu,vu,v 一定不比 不合并u,vu,vu,v以让fau,ufa_u,ufau,u合并 劣。
感性证明:faufa_ufau可能可以和不是uuu的其它小点合并,即使找不到其它可以合并的小点,前面的方案也不必后面的方案劣。
设gig_igi表示考虑完以iii为根的子树,在合并次数最多的情况下,iii上最多有几个小点能和iii的父亲上的小点合并。转移讨论一下即可。
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const int N=2e5+10;
struct Edge{int v,nxt;}e[N<<1];
int cnt,head[N],n;
ll ans,a[N];
void adde(int u,int v){e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u,int fa){ll sum=0,maxn=0,pr;for(int i=head[u];i;i=e[i].nxt){int v=e[i].v;if(v==fa)continue;dfs(v,u);sum+=a[v],maxn=max(maxn,a[v]);}if(sum-maxn>=maxn) pr=sum/2;else pr=sum-maxn;if(sum<=a[u]) ans-=sum;else{pr=min(pr,min(sum-a[u],a[u]));ans-=a[u]+pr;a[u]-=pr;}
}
int main(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);ans+=a[i];}for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);adde(u,v);adde(v,u);}dfs(1,0);printf("%lld\n",ans);return 0;
}