题目描述:
某一天gty在与他的妹子玩游戏。妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问
将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
gty很快计算出了策略。
但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
gty不忍心打击妹子,所以他将这个问题交给了你。
另外由于gty十分绅士,所以他将先手让给了妹子。
输入:
第一行两个数字,n和L,n<=5*10^4,L<=10^9
第二行n个数字,表示每个节点初始石子数。
接下来n-1行,每行两个整数u和v,表示有一条从u到v的边。
接下来一行一个数m,表示m组操作。
接下来m行,每行第一个数字表示操作类型
若为1,后跟一个数字v,表示询问在v的子树中做游戏先手是否必胜。
若为2,后跟两个数字x,y表示将节点x的石子数修改为y。
若为3,后跟三个数字u,v,x,表示为u节点添加一个儿子v,初始石子数为x。
在任意时刻,节点数不超过5*10^4。
算法标签:splay,博弈
思路:
首先,对于把石子移到子树的根的问题其实是一个阶梯nim问题,倘若把奇数层的节点异或后值为0,则先手必败,其余必胜。
对于修改操作,用splay维护,在splay中子树的范围确定,从我向后找到第一个深度小于我的点之前的点都是我的子树,其余的都比较好维护。
以下代码:
#include<bits/stdc++.h> #define il inline #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=1e5+5; int head[N],ne[N<<1],to[N<<1],tot,rt; int n,l,a[N],mnd[N],m,cnt,sum[N][2],d[N],num[N],son[N][2],sz[N],last,fa[N]; il int read(){int x;char ch;_(!);x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return x;} il void insert(int x,int y){ne[++tot]=head[x];head[x]=tot;to[tot]=y;} il void dfs(int x,int fa){ num[++cnt]=x; for(int i=head[x];i;i=ne[i]){ if(fa==to[i])continue; d[to[i]]=d[x]+1;dfs(to[i],x); } } il void update(int x){ sz[x]=sz[son[x][0]]+sz[son[x][1]]+1; sum[x][1]=sum[son[x][1]][1]^sum[son[x][0]][1]; sum[x][0]=sum[son[x][1]][0]^sum[son[x][0]][0]; sum[x][d[x]&1]^=a[x];mnd[x]=d[x]; if(son[x][0])mnd[x]=min(mnd[x],mnd[son[x][0]]); if(son[x][1])mnd[x]=min(mnd[x],mnd[son[x][1]]); } il void build(int &x,int l,int r,int now){ int mid=(l+r)>>1;x=num[mid];fa[x]=now; if(l<mid)build(son[x][0],l,mid-1,x); if(mid<r)build(son[x][1],mid+1,r,x); update(x); } il void rotate(int x,int &k){ int y=fa[x],z=fa[y],tp=son[y][1]==x; if(y==k)k=x;else son[z][son[z][1]==y]=x; son[y][tp]=son[x][tp^1];fa[son[y][tp]]=y; son[x][tp^1]=y;fa[y]=x;fa[x]=z; update(y);update(x); } il void splay(int x,int&k){ while(x!=k){ int y=fa[x],z=fa[y]; if(y!=k)rotate(((son[y][1]==x^son[z][1]==y)?x:y),k); rotate(x,k); } } il int find(int x,int k){ if(!x)return 0; if(min(mnd[son[x][0]],d[x])>k)return find(son[x][1],k); if(mnd[son[x][0]]>k)return x; return find(son[x][0],k); } int main() { n=read();l=read();mnd[0]=1e9; for(int i=1;i<=n;i++)a[i]=read()%(l+1); for(int i=1;i<n;i++){int x=read(),y=read();insert(x,y);insert(y,x);} d[1]=1;num[++cnt]=1e5+1;dfs(1,0);num[++cnt]=1e5+2; build(rt,1,cnt,0); m=read(); while(m--){ int op=read(); if(op==1){ int x=read()^last; splay(x,rt); int y=find(son[x][1],d[x]); splay(y,son[x][1]); int res=sum[son[y][0]][(d[x]&1)==0]; if(!son[y][0]||!res)puts("No"); else puts("Yes"),++last; } else if(op==2){ int x=read()^last;a[x]=(read()^last)%(l+1); for(;x;x=fa[x])update(x); } else{ int x=read()^last,z=read()^last,y; splay(x,rt);y=son[x][1];while(son[y][0])y=son[y][0]; a[z]=(read()^last)%(l+1),d[z]=d[x]+1; if(!y)fa[z]=x,son[x][1]=z,update(z),update(x); else{ splay(y,son[x][1]);son[y][0]=z;fa[z]=y; update(z);update(y);update(x); } } } return 0; }