题意:
有一棵n个节点的有根树,节点编号为0到n-1,根为0号节点。游戏开始时,第i个节点上有a[i]个石子。两位玩家轮流操作,每次操作玩家可以选择一个节点,并将该节点上的一些石子(个数不能为0)移动到它的父亲节点上去。如果轮到某位玩家时,该玩家没有任何合法的操作可以执行,则判负。
你在游戏中执先手,你想知道当前局面你能否必胜。
思路:
肯定是nim啊,nim肯定和异或有关啊。
其实上面说的也不一定对,先考虑只有深度为一的情况,不难发现当各节点值的异或和为0时是必败态,不然就是必胜态。
然后考虑深度不一定只为一的情况,有这样的策略,如果先手操作了深度为偶数的节点的值(操作后这个值在奇数节点),我们也可以接着操作这个值(把这个值移到它上面的偶数节点)。因为根节点的深度为0(当然这是人为定义的……),所以偶数节点的值总是可以被上述策略移到根节点,所以考虑奇数节点的值就好了。
说的很轻松,但直接想可能还是有点难,建议读者可以多想几个情况考虑下,便于理解。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define MS(x,y) memset(x,y,sizeof(x))
const int MAXN=1e5+5;
struct Edge{
int v,nxt;
}edge[MAXN];
int head[MAXN],edgenum;
void addedge(int u,int v){
edge[edgenum].v=v;
edge[edgenum].nxt=head[u];
head[u]=edgenum++;
}
int n,mx;
int dep[MAXN],val[MAXN];
void dfs(int u,int d){
mx=max(mx,d);
dep[d]^=val[u];
for(int i=head[u];~i;i=edge[i].nxt){
int &v=edge[i].v;
dfs(v,d+1);
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
edgenum=mx=0;
for(int i=0;i<n;++i) head[i]=-1,dep[i]=0;
for(int i=1,u;i<n;++i){
scanf("%d",&u);
addedge(u,i);
}
for(int i=0;i<n;++i){
scanf("%d",val+i);
}
dfs(0,0);
int ans=0;
for(int i=1;i<=mx;i+=2){
ans^=dep[i];
}
if(ans) puts("win");
else puts("lose");
}
}