P1131 [ZJOI2007]时态同步

题面

click

前言

题意好模糊,我花了半个小时来看题。

但读懂题之后,你会觉得这题好简单

题解

树形dp OR 贪心

一句话题意:给出一棵边有长度的有根树,花费1的代价可以将任意一条边长增大1,求使得所有叶子到根距离相等的最小花费。

有个结论:若所有叶子到根距离相等,则任意一棵子树的所有叶子到子树根距离相等

自底向上对每一棵子树进行处理,找到子树根到叶子的最大距离,将其他与根相连的边增长到符合要求,然后记录下这个距离用于更上一层的子树处理即可

然后,这道题就没了。

注意,一定要开 long long, 不开 long long 见祖宗

Code:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int N = 5e5+10;
int n,root,tot,u,v,w,ans,head[N],f[N];
bool vis[N];
struct node
{
    int to,net,w;
}e[N<<1];
inline int read()
{
    int s = 0,w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w;
}
void add(int x,int y,int w)
{
    e[++tot].w = w;
    e[tot].to = y;
    e[tot].net = head[x];
    head[x] = tot;
}
void dfs(int x,int fa)
{
    for(int i = head[x]; i; i = e[i].net)
    {
        int to = e[i].to;
        if(to == fa) continue;
        dfs(to,x);
        f[x] = max(f[x],f[to]+e[i].w);//找子树中最长链
    }
    for(int i = head[x]; i; i = e[i].net)
    {
        int to = e[i].to;
        if(to == fa) continue;
        ans += f[x] - (f[to]+e[i].w);//计算每个点的贡献
    }
}
signed main()
{
    n = read(); root = read();
    for(int i = 1; i <= n-1; i++)
    {
        u = read(); v = read(); w = read();
        add(u,v,w); add(v,u,w);
    }
    dfs(root,root);
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/genshy/p/13582394.html