P1131 【ZJOI2007】 时态同步

#Description [题面](https://www.luogu.org/problem/P1131) 给你一颗有根树,你只能增加一条边的边权,最后需要使得根到每个叶子节点的距离相等 #Solution 一道有点贪心意味的DP题,假设一开始根节点到叶子节点的最远距离为d,考虑到只能加边权不能减边权,**显然最终根节点到所有叶子节点的距离d2一定等于d** **所以整个过程是一个将每条路径长度“对齐”的过程** 我们进行树形DP,从叶子节点到根节点转移。设当前节点是u,那么必须保证向上传递时u到它的子树内的每个叶子节点距离相等,否则就永远“对不齐”了。 ![](https://img2018.cnblogs.com/blog/1564177/201910/1564177-20191024153003328-1694011439.png)

就拿上面这个例子来说,假如dis(a,u)!=dis(b,u),那么对u上面的边(i)无论怎么修改,a,b向上的距离是同等增大的,dis(a,fa)一定不等于dis(b,fa)(类似于分配律)
我们为确保答案合法,一定要在u节点是保证dis(u,a)=dis(u,b),即让它到子树中每个叶子节点距离相等,所以可以改变jk变使他们对齐,只需要都加成u到叶子节点距离的最大值即可

这样做一定能确保最终所有距离相等,且我们在尽可能向上的边(如果再往上就是i边,修改不能使答案合法)修改,类似于分配的思想,一定比在下面修改花费的代价更小。(因为在上面+2等效于对每条路径+2,所以在合法的情况下越往上越优)

在代码实现上,我们先要预处理每个节点到子树中的叶子结点的最大距离maxx[u],方便后面对齐操作计算代价使用,在回溯的时候搞一下
然后再次dfs做树形dp统计答案即可(事实上可以放一块,但是我懒得写)
记得开long long

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#define re register
#define maxn 500010
#define int long long
using namespace std;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
struct Edge{
	int v,w,nxt;
}e[maxn<<2];
int to_l[maxn],tmp[maxn],cnt2,maxx[maxn];
int max_dis,x,y,z,root,head[maxn],cnt,n,dp[maxn];
inline void add(int u,int v,int w)
{
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs1(int u,int fa)
{
	for(int i=head[u];i;i=e[i].nxt)
	{
		int ev=e[i].v;
		if(ev==fa) continue;
		dfs1(ev,u);
		maxx[u]=max(maxx[ev]+e[i].w,maxx[u]);
	}
}
void dfs2(int u,int fa)
{
	for(int i=head[u];i;i=e[i].nxt)
	{
		int ev=e[i].v;
		if(ev==fa) continue;
		dfs2(ev,u);
		dp[u]+=(maxx[u]-(maxx[ev]+e[i].w));//计算对齐需要的花费 
		dp[u]+=dp[ev];//不要忘了把子树的答案传递上来 
	}
}
signed main()
{
	n=read();
	root=read();
	for(re int i=1;i<n;++i)
	{
		x=read(),y=read(),z=read();
		add(x,y,z),add(y,x,z);
	}
	dfs1(root,0);//预处理 
	dfs2(root,0);//DP  和上面的放一个函数里也行
	printf("%lld\n",dp[root]);
	return 0;
}

posted @   __Liuz  阅读(114)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示