题意
给定一棵 (n) 个点的树,以 (1) 为根。开始时,每个节点都有一个硬币,两个人轮流执行以下以下操作:
- 如果当前节点有硬币,取走硬币,该人的操作结束;
- 如果当前节点没有硬币,选择该节点一个有硬币的儿子节点,结束本次操作,否则,回到其父亲节点;
求出先手最多可以得到多少个硬币。((2leq n leq 10^5))
分析
https://www.cnblogs.com/HotPants/p/14402231.html
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+5;
vector<int>pic[N];
int f[N],sz[N];
void dfs(int u)
{
sz[u]=1;
f[u]=1;
vector<int>num;
int sum=0;
for(auto v:pic[u])
{
dfs(v);
sz[u]+=sz[v];
if(sz[v]&1) num.pb(f[v]);
else
{
if(f[v]<0) f[u]+=f[v];
else sum+=f[v];
}
}
sort(num.begin(),num.end());
num.pb(sum);//
for(int i=0;i<num.size();i++)
{
if(i%2==0) f[u]+=num[i];
else f[u]-=num[i];
}
}
int main()
{
int n,p;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d",&p);
pic[p].pb(i);
}
dfs(1);
printf("%d
",(f[1]+n)/2);
return 0;
}