VK Cup 2015 - Round 2 B. Work Group(树形dp)

本文介绍了一种使用动态规划解决特定树形结构问题的方法,即在由n个点构成的树中,每个点有特定权值,目标是在适当选择点的情况下使最终权值和最大化。通过定义状态dp[u][0/1]表示节点u的子树含u时选取点数的奇偶性,利用辅助数组进行高效的状态转移。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

n(n<=2e5)个点构成的树,点i有权值ai(1<=ai<=1e5),

点i能被选当且仅当它的子树(不含i)中选了偶数个点,

适当地选点,使得最后的权值和最大,输出最大权值和

思路来源

https://blog.youkuaiyun.com/qq_24451605/article/details/47375879

题解

dp[u][0/1]代表i的子树(含i)共选了偶数/奇数个

则dp[u][1]=max(dp[u][1],dp[u][0]+a[u])模拟的是选u点的过程

初始情况下,把dp[u][1]初始化得足够小(-INF),

使得在不选儿子的时候,这种情况不可达

从儿子处转移时,由于儿子选偶数个/奇数个独立,

所以用辅助数组辅助转移

代码

#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long ll;
const int INF=0x3f3f3f3f;
const int N=2e5+5;
int n,fa,rt,a[N];
ll dp[N][2],tmp[2];//dp[i][0/1] i的子树(含i)共选了 偶数/奇数 个 
vector<int>E[N];
void add(int u,int v)
{
	E[u].push_back(v);
}
void dfs(int u)
{
	dp[u][0]=0;
	dp[u][1]=-INF;
	for(int i=0;i<E[u].size();++i)
	{
		int v=E[u][i];
		dfs(v);
		tmp[0]=dp[u][0],tmp[1]=dp[u][1];
		dp[u][0]=max(tmp[0]+dp[v][0],tmp[1]+dp[v][1]);
		dp[u][1]=max(tmp[0]+dp[v][1],tmp[1]+dp[v][0]);
	} 
	dp[u][1]=max(dp[u][1],dp[u][0]+a[u]);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
	{
		scanf("%d%d",&fa,&a[i]);
		if(fa==-1)rt=i;
		else add(fa,i);
	}
	dfs(rt);
	printf("%lld\n",max(dp[rt][0],dp[rt][1]));
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值