[ZJOI2007]时态同步

这个题。。。一眼树形DP???

我们通过模拟几组数据可以发现。。。

其实只需要保证每一棵树的边权之和加起来相等。。。

那么这些子树组成的一棵大树。。。就是最终我们要求的。。。

既然这样。。。

我们第一遍需要从叶子结点推到根节点。。。找到这些最大值。。。

我们便于理解。。。这里将树分级。。。叶子结点为1级。。。比它大一号的为2级。。。

以此类推。。。

然后依次枚举每一个以当前节点为根的n级子树的权值和它所在n+1级子树要达到的最大值

这样就可以统计出答案了。。。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500010
using namespace std;

int n,s,x,y,z,f[maxn],head[maxn<<1],num;
long long ans;
bool use[maxn];

struct asd{
    int nxt;
    int to;
    int dis;
} a[maxn<<1];

inline void add(int x,int y,int z)
{
    a[++num].nxt=head[x];
    a[num].to=y;
    a[num].dis=z;
    head[x]=num;
}

inline void dfs1(int u)
{
    use[u]=1;
    for(int i=head[u];i;i=a[i].nxt)
    {
        int to=a[i].to;
        if(!use[to])
        {
            dfs1(to);
            f[u]=max(f[u],f[to]+a[i].dis);
        }
    }
}

inline void dfs2(int u)
{
    use[u]=1;
    for(int i=head[u];i;i=a[i].nxt)
    {
        int to=a[i].to;
        if(!use[to])
        {
            dfs2(to);
            ans+=f[u]-f[to]-a[i].dis;
        }
    }
}

int main()
{
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z); add(y,x,z);
    }
    dfs1(s);
    memset(use,0,sizeof(use));
    dfs2(s);
    printf("%lld
",ans);
    return 0;
}
呆码
原文地址:https://www.cnblogs.com/zzzyc/p/9029174.html