题目大意
有一棵有根树,根节点为 1 1 1,点 i i i的价格为 w i w_i wi。
小W和小H轮流购买树上没有被购买过的点。假设买方购买了点 i i i,则他首先要支付 w i w_i wi元。假设在 i i i到根节点的路径上有 n 1 n_1 n1个点已经被另一个玩家购买,在 i i i的子树中有 n 2 n_2 n2个点被另一个玩家购买,则买家需支付 n 1 n_1 n1元给另一位玩家,另一位玩家需支付 n 2 n_2 n2元给买家。
两人都采用最优策略,如果小W先手,则他最多能得到多少钱(答案可以为负数)?
题解
我们可以把购买一个点的花费看作这个点的价值加上这个点的深度加上以这个点为根的子树的大小,即 w i + d e p i − s i z i w_i+dep_i-siz_i wi+depi−sizi。
为什么呢?我们看所有点都已经被购买之后的图。按上面方法计算,相当于每个点都要给每个祖先一元,同时收每个儿子一元。如果两个点都是一方的点,那么自己支付自己一元,自己收取自己一元,相当于什么都没有。如果两个点不是一方的点,则如题目描述来支付。所以,这种价格的计算方法与题目的价格的计算方法等价。
令 a i = w i + d e p i − s i z i a_i=w_i+dep_i-siz_i ai=wi+depi−sizi(即购买点 i i i的花费),则将 a i a_i ai从小到大排序。因为两人都采用最优策略,所以每次玩家取走的点一定是没有被取走的点中 a a a值最小的,而他的花费就是 a i a_i ai。也就是说,获得这个点,他可以得到 − a i -a_i −ai元。
code
#include<bits/stdc++.h>
using namespace std;
int n,x,tot,d[400005],l[400005],r[400005],dep[200005],siz[200005];
long long ans=0,a[200005];
void add(int xx,int yy){
l[++tot]=r[xx];d[tot]=yy;r[xx]=tot;
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;siz[u]=1;
for(int i=r[u];i;i=l[i]){
dfs(d[i],u);
siz[u]+=siz[d[i]];
}
a[u]=a[u]+dep[u]-siz[u];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=2;i<=n;i++){
scanf("%d",&x);
add(x,i);
}
dfs(1,0);
sort(a+1,a+n+1);
for(int i=1;i<=n;i+=2){
ans+=a[i];
}
printf("%lld",-ans);
return 0;
}