题目链接https://www.luogu.com.cn/problem/P1131
一道挺好想的简单树形DP题目,不过本蒟蒻竟然一遍就过了蓝题挺激动的(还是题目太简单了?)
题意很简单,给你一颗树,树边带权值,给你一个根节点,要求从根结点到叶子结点的路径长度相同,求需要在每条边上加值的最小总和。
我们可以设以下dp[i]表示到 i 结点时需要走的最大路程
拿一个简单的例子如图:
观察一下不难发现dp[i]=max(dp[i],dp[j]+w) j是i的子节点 w是j和i之间的路程
其实就是 子节点到叶子结点路程 加上 到子节点的路程的最大值(因为要和求最小总和,又不可以减少边上的值)
找到最大值后让答案加上 dp[k]-dp[v[i]]-we[i] (其他边需要加上的值)
AC代码如下
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 500010
using namespace std;
typedef long long ll;
int n,s;
int head[N],nxt[N<<1],v[N<<1],we[N<<1];
int cnt;
int fa[N];
ll dp[N];
ll ans;
void add(int from,int to,int weight)
{
cnt++;
we[cnt]=weight;
v[cnt]=to;
nxt[cnt]=head[from];
head[from]=cnt;
}
void dfs(int k)
{
for(int i=head[k];i;i=nxt[i])
{
if(fa[k]!=v[i])
{
fa[v[i]]=k;
dfs(v[i]);
dp[k]=max(dp[k],dp[v[i]]+we[i]);
}
}
for(int i=head[k];i;i=nxt[i])
{
if(fa[k]!=v[i])
{
ans+=dp[k]-dp[v[i]]-we[i];
}
}
}
int main()
{
scanf("%d%d",&n,&s);
for(int i=1;i<n;i++)
{
int a,b,w;
scanf("%d%d%d",&a,&b,&w);
add(a,b,w);
add(b,a,w);
}
dfs(s);
printf("%lld",ans);
return 0;
}
(感觉难度顶多是绿题,。,。)