3729: Gty的游戏
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 335 Solved: 104
[ Submit][ Status][ Discuss]
Description
某一天gty在与他的妹子玩游戏。
妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问
将某个节点的子树中的石子移动到这个节点先手是否有必胜策略。
gty很快计算出了策略。
但gty的妹子十分机智,她决定修改某个节点的石子或加入某个新节点。
gty不忍心打击妹子,所以他将这个问题交给了你。
另外由于gty十分绅士,所以他将先手让给了妹子。
Input
第一行两个数字,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。
Output
对于每个询问,若先手必胜,输出"MeiZ",否则输出"GTY"。
另,数据进行了强制在线处理,对于m组操作,除了类型名以外,都需要异或之前回答为"MeiZ"的个数。
Sample Input
0 0
1 2
1
1 1
Sample Output
HINT
Source
题解:博弈+splay
每次都只能移动不超过m个,所以sg[x]=mex(i=1..min(x,m) sg[x-i]) sg[0]=0
这个sg值肯定不能直接求,所有如果没有什么公式或模型的话,就只能用找规律大法了。
sg[x]=x%(m+1)
那么这个题就变成了一个阶梯博弈问题,因为要不断的加边,所有我用splay维护dfs,对于每个节点要记录偶层的异或值也要记录奇层的异或值,然后查询的时候分清要奇层还是偶层就可以了。
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
#define N 200003
using namespace std;
int n,m,tot,point[N],next[N],v[N];
int deep[N],ch[N][3],fa[N],sg[N][3],key[N],l[N],r[N],sit[N];
int q[N],pos[N],mark[N],cnt,root,sz,val[N];
void add(int x,int y)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int f)
{
deep[x]=deep[f]+1;
q[++cnt]=x; l[x]=cnt;
for (int i=point[x];i;i=next[i])
if (v[i]!=f) dfs(v[i],x);
r[x]=++cnt; q[cnt]=-x;
}
void update(int now)
{
if (mark[now]) sg[now][1]=key[now],sg[now][0]=0;
else sg[now][0]=key[now],sg[now][1]=0;
int l=ch[now][0]; int r=ch[now][1];
sg[now][0]^=sg[l][0]^sg[r][0];
sg[now][1]^=sg[l][1]^sg[r][1];
}
int get(int x)
{
return ch[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x]; int z=fa[y]; int which=get(x);
ch[y][which]=ch[x][which^1]; fa[ch[x][which^1]]=y;
fa[y]=x; ch[x][which^1]=y; fa[x]=z;
if (z) ch[z][ch[z][1]==y]=x;
update(y); update(x);
}
void splay(int x,int tar)
{
for (int f;(f=fa[x])!=tar;rotate(x))
if (fa[f]!=tar) rotate(get(f)==get(x)?f:x);
if (!tar) root=x;
}
int build(int l,int r)
{
if (l>r) return 0;
int mid=(l+r)/2;
int now=++sz;
if (q[mid]>0) key[now]=val[q[mid]],mark[now]=(deep[q[mid]]&1),sit[mid]=now;
else key[now]=0,sit[mid]=now;
ch[now][0]=build(l,mid-1);
if (ch[now][0]) fa[ch[now][0]]=now;
ch[now][1]=build(mid+1,r);
if (ch[now][1]) fa[ch[now][1]]=now;
update(now);
return now;
}
int pre()
{
int now=ch[root][0];
while (ch[now][1]) now=ch[now][1];
return now;
}
int nxt()
{
int now=ch[root][1];
while (ch[now][0]) now=ch[now][0];
return now;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&val[i]),val[i]%=(m+1);
for (int i=1;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
add(x,y);
}
q[++cnt]=0;
dfs(1,0); q[++cnt]=0;
root=build(1,cnt);
for (int i=1;i<=n;i++) l[i]=sit[l[i]],r[i]=sit[r[i]];
int ans=0;
int p; scanf("%d",&p);
for (int i=1;i<=p;i++) {
int opt,x,y,k; scanf("%d",&opt);
if (opt==1) {
scanf("%d",&x); x^=ans;
splay(l[x],0); int t1=pre();
splay(r[x],0); int t2=nxt();
splay(t1,0);
splay(t2,root);
int t=ch[ch[root][1]][0];
if (sg[t][(deep[x]&1)^1]) printf("MeiZ\n"),ans++;
else printf("GTY\n");
}
if (opt==2) {
scanf("%d%d",&x,&k); x^=ans; k^=ans;
k%=(m+1);
splay(l[x],0);
int t1=pre();
int t2=nxt();
splay(t1,0);
splay(t2,root);
int t=ch[ch[root][1]][0];
key[t]=k;
update(t); update(ch[root][1]); update(root);
}
if (opt==3) {
scanf("%d%d%d",&x,&y,&k); x^=ans; y^=ans; k^=ans;
k%=(m+1);
deep[y]=deep[x]+1; int now=++sz;
splay(r[x],0); int t1=pre();
splay(t1,0);
splay(r[x],root);
ch[ch[root][1]][0]=now; fa[now]=ch[root][1];
key[now]=k; mark[now]=deep[y]&1;
l[y]=now; r[y]=++sz; ch[now][1]=sz; fa[sz]=now; update(now);
update(ch[root][1]); update(root);
}
}
}