【luogu2986】 [USACO10MAR]伟大的奶牛聚集 [动态规划 树形dp 树的重心]
树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡
性质:
- 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样
- 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上
- 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置
- 一棵树最多有两个重心,且相邻
可以把有n个点的节点分成n个来看 最后得出结论 找重心!
然后就求答案
#include<bits/stdc++.h> using namespace std; #define Max(x,y) (x)<(y)?(y):(x) #define Min(x,y) (x)<(y)?(x):(y) #define ll long long const int N=100000+5,M=1000000+5,inf=0x3f3f3f3f,P=9999973; int n,sum=0,a[N],size[N],mxs[N],dis[N]; int max_part=inf,zx; ll ans=0; template <class t>void rd(t &x){ x=0;int w=0;char ch=0; while(!isdigit(ch)) w|=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x=w?-x:x; } int head[N],tot=0; struct edge{int v,w,nxt;}e[N<<1]; void add(int u,int v,int w){ e[++tot]=(edge){v,w,head[u]},head[u]=tot; } void dfs(int u,int fa){ size[u]=a[u]; int maxsize=0; for(int i=head[u];i;i=e[i].nxt){ if(e[i].v==fa) continue; dfs(e[i].v,u); size[u]+=size[e[i].v]; maxsize=Max(maxsize,size[e[i].v]); } maxsize=Max(maxsize,sum-size[u]); if(maxsize<max_part) max_part=maxsize,zx=u; } void dfs2(int u,int fa){ for(int i=head[u];i;i=e[i].nxt) if(e[i].v!=fa) dis[e[i].v]=dis[u]+e[i].w,dfs2(e[i].v,u); } int main(){ freopen("in.txt","r",stdin); rd(n); for(int i=1;i<=n;++i) rd(a[i]),sum+=a[i]; for(int i=1,u,v,w;i<n;++i) rd(u),rd(v),rd(w),add(u,v,w),add(v,u,w); dfs(1,0); dis[zx]=0; dfs2(zx,0); for(int i=1;i<=n;++i) ans+=(ll)dis[i]*a[i]; printf("%lld",ans); return 0; }