hdu5996 dingyeye loves stone

问题描述

dingyeye喜欢和你玩石子游戏。

dingyeye有一棵n个节点的有根树,节点编号为0到n-1,根为0号节点。游戏开始时,第i个节点上有a[i]个石子。两位玩家轮流操作,每次操作玩家可以选择一个节点,并将该节点上的一些石子(个数不能为0)移动到它的父亲节点上去。如果轮到某位玩家时,该玩家没有任何合法的操作可以执行,则判负。

你在游戏中执先手,你想知道当前局面你能否必胜。

输入描述

本题有多组数据,第一行为一个非负整数T,表示数据组数。

对于每组数据,第一行一个整数n,表示节点数目。

接下来一行为n−1个整数fa[1]⋯fa[n−1],分别描述了除根节点外每个点的父亲。方便起见,保证0<=fa[i]< i。
接下来一行为n个非负整数a[0]⋯a[n−1],分别描述了每个点初始的石子数。保证0≤a[i]<134217728。

1≤T≤100,1≤n≤100000。

保证n>100的测试点数目不超过77个。

输出描述

对于每组数据,输出一行,若先手必胜则输出”win”,否则输出”lose”(不含引号)。

输入样例

2
2
0
1000 1
4
0 1 0
2 3 3 3

输出样例

win
lose

题解:阶梯博弈,可以考虑把这个问题转化成Nim博弈:我们考虑到可以把奇数阶梯的数抽象出来,那么可以把从奇数阶梯的数看成Nim,将石子移到父节点可以看作“取石子”,如果是从偶数阶梯的取石子到父节点,我们可以“模拟”这次操作将这些石子继续搬运到下一个父节点,也就是跳过了奇数阶层,那么对奇数阶层做一次异或运算即可。
为什么要用奇数阶层而不是偶数阶层呢?第0层石子是不可动的,相当于是你先移动而最后移到0层的操作是你的对手完成的,这时候你会破坏Nim结构而使胜负结果不好判定。

#include<cstdio>
#include<cmath>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<list>
#define pi 4*atan(1)
#define eps 1e-10
#define INF 0x3f3f3f3f
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define FF(i,n) for(int i = 0 ; i < n ; i++)
#define F(i,n) for(int i = 1 ; i <= n ; i++)
#define maxn 100000+10
#define mod 200907
#define met(a) memset(a,0,sizeof(a))
typedef long long LL;
//typedef __int64 LL;
using namespace std;
/*void read(int &x){
    #define CH getchar()
    char ch; x=0;for(ch=CH;ch<'0'||ch>'9';ch=CH);
    for(;ch>='0'&&ch<='9';x=x*10+ch-48,ch=CH);
}*/ 
LL a[maxn];
vector<LL> v[maxn];
LL flag;
void dfs(int x,int deep)
{
    if(deep&1)flag^=a[x];
    for(int i=0;i<v[x].size();i++)
    {
        dfs(v[x][i],deep+1);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--)
    {
        LL n;
        cin>>n;
        for(int i=0;i<=n;i++)
        {
            v[i].clear();
        }
        LL x;
        for(int i=1;i<=n-1;i++)
        {
            cin>>x;
            v[x].push_back(i);
        }
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
        }
        flag=0;
        dfs(0,0);
        if(flag)cout<<"win"<<endl;
        else cout<<"lose"<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值