BZOJ1060: [ZJOI2007]时态同步

【传送门:BZOJ1060


简要题意:

  给出一棵树和根节点的编号,有一种道具可以使得一条边的权值+1,请问最少改变多少次使得根到所有叶子节点的权值和相等


题解:

  首先我们可以确定达到根到所有叶子节点的权值和相等时,这个权值和一定是最大的根到叶子节点的链的权值和

  所以我们用树形DP来维护f[i],f[i]表示从i点到叶子节点的最大权值和

  然后ans=Σf[i]-f[y]-a[k].d(y表示i的儿子节点,a[k].d表示这条边的权值)


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
LL f[510000];
struct node
{
    int x,y,next;
    LL d;
}a[1100000];int len,last[510000];
void ins(int x,int y,int d)
{
    len++;
    a[len].x=x;a[len].y=y;a[len].d=d;
    a[len].next=last[x];last[x]=len;
}
LL ans;
void dfs(int x,int fa)
{
    f[x]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa)
        {
            dfs(y,x);
            f[x]=max(f[x],f[y]+a[k].d);
        }
    }
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        if(y!=fa) ans+=f[x]-f[y]-a[k].d;
    }    
}
int main()
{
    int n;
    scanf("%d",&n);
    int root;
    scanf("%d",&root);
    len=0;memset(last,0,sizeof(last));
    for(int i=1;i<n;i++)
    {
        int x,y,d;
        scanf("%d%d%d",&x,&y,&d);
        ins(x,y,d);ins(y,x,d);
    }
    ans=0;
    dfs(root,0);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-03-20 07:32  Star_Feel  阅读(100)  评论(0编辑  收藏  举报