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

题目

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

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

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

思路来源

https://blog.csdn.net/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;
} 
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/101209607