


学习博客: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\n",ans);
55 return 0;
56 }
来源:https://www.cnblogs.com/wsy107316/p/12345748.html