【luogu2986】 [USACO10MAR]伟大的奶牛聚集 [动态规划 树形dp 树的重心]

P2986 [USACO10MAR]伟大的奶牛聚集

树的重心:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡

性质:

  • 树中所有点到某个点的距离和中,到重心的距离和是最小的,如果有两个距离和,他们的距离和一样
  • 把两棵树通过一条边相连,新的树的重心在原来两棵树重心的连线上
  • 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置
  • 一棵树最多有两个重心,且相邻

可以把有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;
}

猜你喜欢

转载自www.cnblogs.com/lxyyyy/p/11209690.html