P1131 [ZJOI2007]时态同步
题面
前言
题意好模糊,我花了半个小时来看题。
但读懂题之后,你会觉得这题好简单
题解
树形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;
}