CF533B
RabbieWjy
题目描述
公司有 n n n 个人, 1 1 1 是总裁,每个人有一个直接上司。每一个人有一个权值 a i a_i ai,要求找一个集合,使集合中所有人权值之和最大。其中每一个人的下属(直接,间接)总数都必须是偶数。输出最大权值。
1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1≤n≤2×105, 1 ≤ a i ≤ 1 0 5 1 \leq a_i \leq 10^5 1≤ai≤105。
解题方法
树形 DP。
枚举每个节点,维护 f [ x ] [ 1 ] f[x][1] f[x][1] 代表在 x x x 为根的子树中,选取奇数个节点的最大权值和; f [ x ] [ 0 ] f[x][0] f[x][0] 代表在 x x x 为根的子树中,选取偶数个节点的最大权值和(记录选奇数个节点是因为有可能不选节点 x x x,而最后用这奇数个节点拼成偶数个节点)。
转移很显然:
f [ x ] [ 1 ] = max j ∈ s o n [ x ] ( f [ x ] [ 1 ] + f [ u ] [ 0 ] , f [ x ] [ 0 ] + f [ u ] [ 1 ] ) f [ x ] [ 0 ] = max j ∈ s o n [ x ] ( f [ x ] [ 1 ] + f [ u ] [ 1 ] , f [ x ] [ 0 ] + f [ u ] [ 0 ] ) f [ x ] [ 1 ] = max ( f [ x ] [ 1 ] , f [ x ] [ 0 ] + v a l [ x ] ) f[x][1]=\max \limits _{j\in son[x]} (f[x][1]+f[u][0],f[x][0]+f[u][1])\\ f[x][0]=\max \limits _{j \in son[x]} (f[x][1]+f[u][1],f[x][0]+f[u][0])\\ f[x][1]=\max (f[x][1],f[x][0]+val[x]) f[x][1]=j∈son[x]max(f[x][1]+f[u][0],f[x][0]+f[u][1])f[x][0]=j∈son[x]max(f[x][1]+f[u][1],f[x][0]+f[u][0])f[x][1]=max(f[x][1],f[x][0]+val[x])
即用除以 u u u 为根的子树外的某些节点和以 u u u 为根的子树的某些节点拼起来,取最大值,或用 x x x 的后代们的某些与 x x x 拼起来,取最大值。
最后答案就是 f [ 1 ] [ 1 ] f[1][1] f[1][1]。
也就是取偶数个 x x x 的后代们以及 x x x 或者不取 x x x,取奇数个 x x x 的后代们。
代码实现
注意初始化, f [ x ] [ 1 ] f[x][1] f[x][1] 初始不可能,应该初始化为 − i n f -inf −inf。
注意开 long long。
注意更新 f f f 数组时,记录原来是多少。
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll inf = 1e18;
int n;
ll val[200010];
int to[200010],nxt[200010],head[200010],Cnt[200010],cnt;
ll f[200010][3];
void add(int x,int y)
{
to[++ cnt] = y;
nxt[cnt] = head[x];
head[x] = cnt;
Cnt[x] ++;
}
void dp(int x)
{
if (!Cnt[x])
{
f[x][1] = val[x];
return ;
}
f[x][0] = 0,f[x][1] = -inf;
for (int i = head[x];i;i = nxt[i])
{
int u = to[i];
dp(u);
ll tmp1 = f[x][1],tmp0 = f[x][0];
f[x][0] = max(f[x][0] + f[u][0],f[x][1] + f[u][1]);
f[x][1] = max(tmp1 + f[u][0],tmp0 + f[u][1]);
}
f[x][1] = max(f[x][1],f[x][0] + val[x]);
}
int main()
{
scanf("%d",&n);
for (int i = 1;i <= n;i ++)
{
int x;
scanf("%d%lld",&x,val + i);
if (i != 1) add(x,i);
}
dp(1);
printf("%lld\n",f[1][1]);
}