可以水水换根的,不过我是另一种做法:(按点权)找重心,事实上这是重心的一个性质
考虑换根的这个过程,当我们把点放在重心时,我们移动这个点有两种情况:
1.移动到最大的那个子树里
可以发现这个最大的子树的$size$不可能超过其余子树的$size$之和(最多是有两个重心的时候等于其他子树的$size$之和),不然你找的是假重心
2.移动到其他的子树里
显然这样只会让答案变差
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=100005; 6 long long dis[N],val[2*N],num[N],maxx[N],siz[N]; 7 int p[N],noww[2*N],goal[2*N],vis[N]; 8 long long ans,tot,t3,maxn=1e16; 9 int n,c,t1,t2,cnt; 10 void link(int f,int t,long long v) 11 { 12 noww[++cnt]=p[f],p[f]=cnt; 13 goal[cnt]=t,val[cnt]=v; 14 } 15 void MARK(int nde,int fth) 16 { 17 siz[nde]=num[nde]; 18 for(int i=p[nde];i;i=noww[i]) 19 if(goal[i]!=fth) 20 { 21 MARK(goal[i],nde); 22 siz[nde]+=siz[goal[i]]; 23 maxx[nde]=max(maxx[nde],siz[goal[i]]); 24 } 25 maxx[nde]=max(maxx[nde],tot-siz[nde]); 26 if(maxx[nde]<maxn) maxn=maxx[nde],c=nde; 27 } 28 void DFS(int nde,int fth) 29 { 30 for(int i=p[nde];i;i=noww[i]) 31 if(goal[i]!=fth) 32 { 33 dis[goal[i]]=dis[nde]+val[i]; 34 DFS(goal[i],nde); 35 } 36 } 37 int main() 38 { 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++) 41 scanf("%lld",&num[i]),tot+=num[i]; 42 for(int i=1;i<n;i++) 43 { 44 scanf("%d%d%lld",&t1,&t2,&t3); 45 link(t1,t2,t3),link(t2,t1,t3); 46 } 47 c=1; MARK(1,0); DFS(c,0); 48 for(int i=1;i<=n;i++) 49 ans+=dis[i]*num[i]; 50 printf("%lld",ans); 51 return 0; 52 }