传送门
挺蛋疼的一道题
连想带做搞了一晚上晚自习+下午两节课
博弈方面还是很好弄的,就是“阶梯问题”+“Nim取模游戏”
分别维护深度为奇数和偶数的节点的sg函数
然后直接查询就可以了
问题在于如何实时添加新节点
这个难了我好久
聪哥提出利用分块重构+暴力思想,蒟蒻不是很懂
考虑到子树查询多与dfs序有关,想用splay维护一下
然后怎么维护并实时查询每个节点的dfs序成了难题
又难了好久……
后来联想到了ST表维护LCA(???),然后莫名奇妙就想到了把dfs序拆成两个点
因为之前做树链剖分的时候dfs序只是1-n,而这里可以把树上的节点dfs序记录两次,变成1-2n,下面详细说一下
设当前dfs到的节点为x,dfs序的计数器为cnt,代表x的入dfs序为L[x],出dfs序为R[x](为了方便表达,我在代码中将它们编号为2·x-1和2·x),splay中节点i的权值为w[i](splay中按w为关键字进行排序)
节点x进入dfs时cnt++,w[L[x]]=cnt,扫完所有该节点子树,离开dfs时再cnt++,w[R[x]]=cnt
最后把所有的L[x]和R[x]都扔进splay中
这样splay中就有2n个节点了
怎么维护sg函数呢?
再加一个数组b
其中b[L[x]]=a[x],b[R[x]]=0
这样就能解决问题了
操作1
把L[x]的前驱节点旋到根,然后把R[x]的后继旋到根的右儿子,这样根的右儿子的左子树就是所求的范围了
操作2
直接把要改的节点x的L[x]旋到根,直接改就可以了
操作3
设插入节点为y,插入到x的下面,石子数为z
像上面普通的插入节点类似,但是要注意,把L[x]旋到根,然后把根的右子树的w全加2
w[L[y]]=w[L[x]]+1,w[R[y]]=w[L[x]]+2
虽然艰难地A了
还是要吐槽一下
自己实在写的太烂
操作1中不知道为什么我必须先把L[x],R[x]分别旋到根,再进行后续操作才能把lazy标记施放下去
还有就是范围必须开到60000才能过,不然就RE
之前并没有写过splay维护dfs序,这次YY了好久才写出来这个常数大代码长的东西
要是在考场上调这种自己没写过的东西,八成是作大死了
决定等会去看一下别人是怎么写的……
还是要好好学习才行啊~~
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define M 60005
using namespace std;
int n,m,P,root,tot,cnt;
int a[M],b[M<<1],first[M],fa[M<<1],w[M<<1],son[M<<1]
[2],L[M],R[M],s0[M<<1],s1[M<<1],dep[M],lazy[M<<1],stacks[M<<1];
bool T[M<<1];
struct edge{
int v,next;
}e[M<<1];
void add(int x,int y)
{
e[++tot]=(edge){y,first[x]};first[x]=tot;
e[++tot]=(edge){x,first[y]};first[y]=tot;
}
int in()
{
int t=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void dfs(int x,int fa)
{
L[x]=x*2-1;R[x]=x*2;
w[L[x]]=++cnt;
T[L[x]]=dep[x];
if (dep[x]) s1[L[x]]=a[x];
else s0[L[x]]=a[x];
for (int i=first[x];i;i=e[i].next)
if (e[i].v!=fa)
dep[e[i].v]=!dep[x],
dfs(e[i].v,x);
w[R[x]]=++cnt;
}
void ct(int x)
{
s0[x]=s1[x]=0;
if (T[x]) s1[x]^=b[x];
else s0[x]^=b[x];
if (son[x][0]!=-1)
s1[x]^=s1[son[x][0]],
s0[x]^=s0[son[x][0]];
if (son[x][1]!=-1)
s1[x]^=s1[son[x][1]],
s0[x]^=s0[son[x][1]];
}
void pushdown(int x)
{
if (!lazy[x]) return;
if (son[x][0]!=-1)
lazy[son[x][0]]+=lazy[x],
w[son[x][0]]+=lazy[x];
if (son[x][1]!=-1)
lazy[son[x][1]]+=lazy[x],
w[son[x][1]]+=lazy[x];
lazy[x]=0;
}
void rorate(int x,bool f)
{
int y=fa[x];
son[y][!f]=son[x][f];
if (son[x][f]!=-1)fa[son[x][f]]=y;
fa[x]=fa[y];
if (fa[y]!=-1)
if (son[fa[y]][0]==y) son[fa[y]][0]=x;
else son[fa[y]][1]=x;
son[x][f]=y;
fa[y]=x;
ct(y);ct(x);
}
void splay(int x,int goal)
{
int t=x;
stacks[++stacks[0]]=x;
for (;fa[x]!=goal;)x=fa[x],stacks[++stacks[0]]=x;
x=t;
for (;stacks[0];--stacks[0]) pushdown(stacks[stacks[0]]);
for (int y;fa[x]!=goal;)
{
y=fa[x];
if (fa[y]==goal)
if (son[y][0]==x) rorate(x,1);
else rorate(x,0);
else if (son[fa[y]][0]==y)
{
if (son[y][0]==x) rorate(y,1);
else rorate(x,0);
rorate(x,1);
}
else
{
if (son[y][1]==x) rorate(y,0);
else rorate(x,1);
rorate(x,0);
}
}
if (goal==-1) root=x;
}
int Kth(int x)
{
int now=root;
for (;;)
{
pushdown(now);
if (w[now]>x)
if (son[now][0]==-1) return now;
else now=son[now][0];
else if (w[now]<x)
if (son[now][1]==-1) return now;
else now=son[now][1];
else return now;
}
}
void insert(int x)
{
if (root==-1) return void(root=x);
int now=root;
for (;;)
{
pushdown(now);
if (!T[x]) s0[now]^=b[x];
else s1[now]^=b[x];
if (w[now]>w[x])
if (son[now][0]==-1)
{son[now][0]=x;fa[x]=now;break;}
else
now=son[now][0];
else
if (son[now][1]==-1)
{son[now][1]=x;fa[x]=now;break;}
else
now=son[now][1];
}
splay(x,-1);
}
main()
{
n=in();P=in()+1;
for (int i=1;i<=n;++i) a[i]=in()%P;
for (int i=1;i<n;++i) add(in(),in());
dfs(1,0);
memset(son,-1,sizeof(son));
memset(fa,-1,sizeof(fa));
root=-1;
insert(0);
for (int i=1;i<=n;++i)
b[L[i]]=a[i],
insert(L[i]),insert(R[i]);
w[M*2-4]=M*2-4;
insert(M*2-4);
int tp,x,y,z,Mei=0;
for (m=in();m;--m)
{
tp=in();
if (tp==1)
{
x=in()^Mei;
splay(L[x],-1);
splay(R[x],-1);
splay(Kth(w[L[x]]-1),-1);
splay(Kth(w[R[x]]+1),root);
y=s0[son[son[root][1]][0]];
z=s1[son[son[root][1]][0]];
if ((y&&T[L[x]])||(z&&!T[L[x]])) puts("MeiZ"),++Mei;
else puts("GTY");
}
else if (tp==2)
{
x=in()^Mei;y=(in()^Mei)%P;
splay(L[x],-1);
if (T[root]) s1[root]^=b[root];
else s0[root]^=b[root];
b[root]=y;
if (T[root]) s1[root]^=b[root];
else s0[root]^=b[root];
}
else
{
x=in()^Mei;y=in()^Mei;z=(in()^Mei)%P;
splay(L[x],-1);
lazy[son[root][1]]+=2;w[son[root][1]]+=2;
L[y]=2*y-1,R[y]=2*y;
w[L[y]]=w[root]+1,w[R[y]]=w[root]+2;
b[L[y]]=z;
T[L[y]]=!T[root];
insert(L[y]);insert(R[y]);
}
}
}