学习博客:https://blog.csdn.net/LJD201724114126/article/details/85240762?utm_source=app
题解:换根
我们先设sum[u] 等于 以u为根的子树的∑ai (注意没有*距离),再计算以1为根的贡献值res。
这时我们要从父亲节点u向儿子节点v换根,故需要将res的值转化为以v为根的value
首先我们要先 res -= sum[v],因为换根之前,以v为根的子树(包括v)到原根u的深度比换根之后,到新根v的深度少了一,故减去
然后我们sum[u] -= sum[v],因为原来sum[u]表示的是以u为根的值(包括了以v为根),而这时是以v为根的,故sum[u]要减去sum[v],
res += sum[u],因为换根之前,以u为根的子树(包括u)到原根u的深度比换根之后,到新根v的深度多了一,故加上
最后sum[v]+=sum[u],因为v要成为整个树的根,而原来sum[v]不包括以u为根的节点值,故要加上。
换完之后我们再换回来。
这里巧妙的应用了换根,就是先求出任意一个根的结果,然后我们dfs,将相邻的根换一换,求出结果。
AC_Code
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 2e5+10; 5 const int inf=0x3f3f3f3f; 6 #define rep(i,first,last) for(ll i=first;i<=last;i++) 7 #define dep(i,first,last) for(ll i=first;i>=last;i--) 8 struct edge{ll to,nxt;}e[maxn<<1]; 9 ll head[maxn<<1],cnt,a[maxn],n; 10 ll ans,res,sum[maxn]; 11 void addedge(ll u,ll v){ e[++cnt].to=v; e[cnt].nxt=head[u];head[u]=cnt;} 12 void dfs1(ll u,ll fa,ll h){ 13 res+=(h*a[u]); 14 sum[u]=a[u]; 15 for(ll i=head[u];i;i=e[i].nxt){ 16 ll v=e[i].to; 17 if(v==fa) continue; 18 dfs1(v,u,h+1); 19 sum[u]+=sum[v]; 20 } 21 } 22 void dfs2(ll u,ll fa){ 23 ans=max(ans,res); 24 for(ll i=head[u];i;i=e[i].nxt){ 25 ll v=e[i].to; 26 if( v==fa ) continue; 27 28 res-=sum[v]; 29 sum[u]-=sum[v]; 30 res+=sum[u]; 31 sum[v]+=sum[u]; 32 33 dfs2(v,u); 34 35 sum[v]-=sum[u]; 36 res-=sum[u]; 37 sum[u]+=sum[v]; 38 res+=sum[v]; 39 } 40 return ; 41 } 42 signed main() 43 { 44 scanf("%lld",&n); 45 rep(i,1,n) scanf("%lld",&a[i]); 46 ll x,y; 47 rep(i,1,n-1){ 48 scanf("%lld%lld",&x,&y); 49 addedge(x,y); 50 addedge(y,x); 51 } 52 dfs1(1,-1,0); 53 dfs2(1,-1); 54 printf("%lld ",ans); 55 return 0; 56 }