题目
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;
}