[THUPC 2023 初赛] 大富翁

P9133 [THUPC 2023 初赛] 大富翁

题目大意

有一棵有根树,根节点为 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+depisizi

为什么呢?我们看所有点都已经被购买之后的图。按上面方法计算,相当于每个点都要给每个祖先一元,同时收每个儿子一元。如果两个点都是一方的点,那么自己支付自己一元,自己收取自己一元,相当于什么都没有。如果两个点不是一方的点,则如题目描述来支付。所以,这种价格的计算方法与题目的价格的计算方法等价。

a i = w i + d e p i − s i z i a_i=w_i+dep_i-siz_i ai=wi+depisizi(即购买点 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;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值