本文主要是介绍【洛谷P1131】时态同步【树形dp】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目大意:
题目链接:https://www.luogu.org/problem/P1131
给出一棵树以及其一个特殊点,可以选择一些边似的这条边的长度加1。问要使得从特殊点到达所有叶子结点的路径长度一样最少需要增加多少。
思路:
这道题准确来说应该不算 d p dp dp吧
把这个点看做整棵树的根,那么我们就需要让所有叶子到根的距离相同。
假设点 x x x的子树全部满足到叶子的距离相同,那么我们需要维护使得所有叶子到 x x x的距离也相同,那么显然最优方案是把 x x x到他的子节点的距离增加。
我们设 m a x n maxn maxn表示节点 x x x与其叶子节点的最远距离。那么我们就要把它与叶子的边的距离增加至 m a x n maxn maxn。那么我们发现一条边的权值使用过了后就不会再使用,所以我们把边 ( x , y ) ∣ y ∈ s o n x (x,y)|y\in son_x (x,y)∣y∈sonx的距离就设为节点 y y y至其叶子的距离。这样均摊就为 O ( n ) O(n) O(n)。
还是比较简单的。代码也相对较短。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;const int N=500010;
int n,root,tot,f[N],head[N];
ll ans;struct edge
{int next,to;ll dis;
}e[N*2];void add(int from,int to,int dis)
{e[++tot].to=to;e[tot].dis=dis;e[tot].next=head[from];head[from]=tot;
}ll dfs(int x,int fa)
{ll maxn=0;for (int i=head[x];~i;i=e[i].next){int v=e[i].to;if (v!=fa){e[i].dis+=dfs(v,x);maxn=max(maxn,(ll)e[i].dis);}}for (int i=head[x];~i;i=e[i].next)if (e[i].to!=fa) ans+=maxn-(ll)e[i].dis;return maxn;
}int main()
{memset(head,-1,sizeof(head));scanf("%d%d",&n,&root);for (int i=1,x,y,z;i<n;i++){scanf("%d%d%d",&x,&y,&z);add(x,y,z); add(y,x,z);}dfs(root,0);printf("%lld",ans);return 0;
}
这篇关于【洛谷P1131】时态同步【树形dp】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!