Description
某一天gty在与他的妹子玩游戏。
妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
gty很快计算出了策略。
但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
gty不忍心打击妹子,所以他将这个问题交给了你。
另外由于gty十分绅士,所以他将先手让给了妹子。
Solution
这题一看就先推一推SG函数,然后就维护一下这棵树,用
d
f
s
dfs
dfs序看待的话就变成一个维护序列问题,支持查询区间异或和还有插入修改。
还有一个问题就是怎么获得一棵子树的区间,直接每个点按照入栈出栈序插两个点就行了。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=60010;
const int inf=2147483647;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
map<int,int>id;int ID=0;
int n,L,pos[Maxn][2],ll[Maxn],stone[Maxn],dep[Maxn],tot=0;
int sg(int d,int x)
{
if(!(d&1))return 0;
return x%(L+1);
}
vector<int>h;
struct Edge{int y,next;}e[Maxn<<1];
int last[Maxn],len=0;
void ins(int x,int y)
{
int t=++len;
e[t].y=y;e[t].next=last[x];last[x]=t;
}
void dfs(int x,int ff)
{
h.push_back(x);dep[x]=dep[ff]+1;
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==ff)continue;
dfs(y,x);
}
h.push_back(x);
}
int fa[Maxn<<1],son[Maxn<<1][2],v[Maxn<<1][2],sum[Maxn<<1][2],sz[Maxn<<1],root;
void up(int x)
{
int lc=son[x][0],rc=son[x][1];
sum[x][0]=v[x][0],sum[x][1]=v[x][1],sz[x]=1;
if(lc)sum[x][0]^=sum[lc][0],sum[x][1]^=sum[lc][1],sz[x]+=sz[lc];
if(rc)sum[x][0]^=sum[rc][0],sum[x][1]^=sum[rc][1],sz[x]+=sz[rc];
}
int build(int l,int r)
{
if(l>r)return 0;
if(l==r)return l;
int mid=l+r>>1;
son[mid][0]=build(l,mid-1);if(son[mid][0])fa[son[mid][0]]=mid;
son[mid][1]=build(mid+1,r);if(son[mid][1])fa[son[mid][1]]=mid;
up(mid);
return mid;
}
void rotate(int x)
{
int y=fa[x],z=fa[y],w=(son[y][0]==x);
son[y][w^1]=son[x][w];if(son[x][w])fa[son[x][w]]=y;
son[z][son[z][1]==y]=x;fa[x]=z;
son[x][w]=y;fa[y]=x;
up(y);up(x);
}
void splay(int x,int rt)
{
while(fa[x]!=rt)
{
int y=fa[x],z=fa[y];
if(z==rt)rotate(x);
else rotate(((son[z][1]==y)==(son[y][1]==x))?y:x),rotate(x);
}
if(!rt)root=x;
}
void split(int l,int r){splay(l,0),splay(r,l);}
int find_by_rank(int rk)
{
int x=root;
while(rk!=sz[son[x][0]]+1)
{
int lc=son[x][0],rc=son[x][1];
if(rk<=sz[lc])x=lc;
else rk-=(sz[lc]+1),x=rc;
}
return x;
}
void insert(int ff,int x,int V)
{
stone[x]=V;dep[x]=dep[ff]+1;
sz[++tot]=1;pos[x][0]=tot;
v[tot][0]=sum[tot][0]=sg(dep[x],stone[x]);
v[tot][1]=sum[tot][1]=sg(dep[x]+1,stone[x]);
sz[++tot]=1;pos[x][1]=tot;
v[tot][0]=sum[tot][0]=v[tot][1]=sum[tot][1]=0;
int l,r;
splay(pos[ff][1],0);
l=find_by_rank(sz[son[pos[ff][1]][0]]),r=pos[ff][1];
split(l,r);
son[r][0]=tot-1;fa[tot-1]=r;
son[tot-1][1]=tot;fa[tot]=tot-1;
up(tot-1),up(r),up(l);
}
int main()
{
n=read(),L=read();
for(int i=1;i<=n;i++)stone[i]=read(),id[i]=++ID;
for(int i=1;i<n;i++)
{
int x=read(),y=read();
ins(x,y),ins(y,x);
}
dep[0]=-1;dfs(1,0);
pos[0][0]=++tot;
sum[tot][0]=sum[tot][1]=v[tot][0]=v[tot][1]=0;
sz[tot]=1;
for(int i=0;i<h.size();i++)
{
int x=h[i];
pos[x][ll[x]++]=++tot;
if(ll[x]==1)
{
sum[tot][0]=v[tot][0]=sg(dep[x],stone[x]);
sum[tot][1]=v[tot][1]=sg(dep[x]+1,stone[x]);
sz[tot]=1;
}
else
{
sum[tot][0]=sum[tot][1]=v[tot][0]=v[tot][1]=0;
sz[tot]=1;
}
}
pos[0][1]=++tot;
sum[tot][0]=sum[tot][1]=v[tot][0]=v[tot][1]=0;
sz[tot]=1;
root=build(1,tot);
int m=read(),cnt=0;
while(m--)
{
int op=read(),x=id[read()^cnt],y,z;
if(op==1)
{
int l,r;
splay(pos[x][0],0);
l=find_by_rank(sz[son[pos[x][0]][0]]);
splay(pos[x][1],0);r=find_by_rank(sz[son[pos[x][1]][0]]+2);
split(l,r);
if(!(dep[x]&1))
{
if(!(sum[son[r][0]][0]^v[pos[x][0]][0]))puts("GTY");
else puts("MeiZ"),cnt++;
}
else
{
if(!(sum[son[r][0]][1]^v[pos[x][0]][1]))puts("GTY");
else puts("MeiZ"),cnt++;
}
}
else if(op==2)
{
y=(read()^cnt);stone[x]=y;
splay(pos[x][0],0);
v[pos[x][0]][0]=sg(dep[x],stone[x]);
v[pos[x][0]][1]=sg(dep[x]+1,stone[x]);
up(x);
}
else
{
id[read()^cnt]=++ID,z=(read()^cnt);
insert(x,ID,z);
}
}
}