题面
略
题解
可以发现,我们只需考虑离根节点距离为奇数的节点的权值。
因为如果距离为偶数,则后手可以重复先手的步骤。
由于要求每次只能取不超过m个节点,于是我们的权值需要对(m+1)取模。
每次是否只能对同一节点上的石子进行操作,这个题意并没有交代清楚,但是既然AC代码都是取的异或,那说明应该的确每次只能动一个节点。
由于节点的权值以及树的形状会发生变化,又强制在线,所以我们采用LCT维护。每个节点记录子树中深度为奇数/偶数的点的权值异或和。有的题解开了两棵动态树,分别记录奇数,偶数节点信息;其实开一棵就行了,记录两套权值即可。
有几个细节问题:
- 不用makeroot,也不用打rev标记。
- 询问深度为奇数/偶数的节点时,查看子树中偶数/奇数深度节点的信息。这样得到的才是到当前节点距离为奇数的节点的异或和.
代码
很丑!!!
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 60000
void _r(int& x)
{
char c=getchar();
while(c<'0'||c>'9')
{
c=getchar();
}
for(x=0;c>='0'&&c<='9';c=getchar())
{
x=(x<<1)+(x<<3)+c-'0';
}
return ;
}
int n,m,a[MAXN],cnt,Q;
int dep[MAXN],fa[MAXN],ch[MAXN][2],v1[MAXN],v2[MAXN],t1[MAXN],t2[MAXN];
int st[MAXN],top;
int Next[MAXN*2],End[MAXN*2],Last[MAXN],e=0;
void add(int x,int y)
{
End[++e]=y;
Next[e]=Last[x];
Last[x]=e;
return ;
}
inline bool notroot(int x)
{
return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
void zg(int x,int d)
{
int y=fa[x],z=fa[y];
if(notroot(y))
{
if(ch[z][0]==y)
{
ch[z][0]=x;
}
else
{
ch[z][1]=x;
}
}
fa[x]=z;
ch[y][d]=ch[x][!d];
fa[ch[y][d]]=y;
ch[x][!d]=y;
fa[y]=x;
return ;
}
void push(int p)
{
if(t1[p])
{
v1[p]^=t1[p];
t1[ch[p][0]]^=t1[p];
t1[ch[p][1]]^=t1[p];
t1[p]=0;
}
if(t2[p])
{
v2[p]^=t2[p];
t2[ch[p][0]]^=t2[p];
t2[ch[p][1]]^=t2[p];
t2[p]=0;
}
return ;
}
void splay(int x)
{
st[top=1]=x;
for(int i=x;notroot(i);i=fa[i])
{
st[++top]=fa[i];
}
for(;top;--top)
{
push(st[top]);
}
int y,z;
while(notroot(x))
{
y=fa[x];
z=fa[y];
if(notroot(y))
{
if(ch[z][0]==y^ch[y][0]==x)
{
zg(x,ch[fa[x]][1]==x);
}
else
{
zg(y,ch[fa[y]][1]==y);
}
}
zg(x,ch[fa[x]][1]==x);
}
return ;
}
void access(int x)
{
for(int t=0;x;t=x,x=fa[x])
{
splay(x);
ch[x][1]=t;
}
return ;
}
void rt(int x)
{
access(x);
splay(x);
return ;
}
inline void link(int x,int y)
{
fa[x]=y;
return ;
}
void change(int x,int p,int d)
{
rt(1);
rt(x);
if(p)
{
t1[x]^=d;
}
else
{
t2[x]^=d;
}
return ;
}
int query(int x,int p)
{
rt(1);
rt(x);
if(p)
{
return v1[x];
}
else
{
return v2[x];
}
}
void dfs(int x,int ff)
{
dep[x]=dep[ff]+1;
for(int t=Last[x],y;t;t=Next[t])
{
y=End[t];
if(y!=ff)
{
link(y,x);
dfs(y,x);
}
}
return ;
}
int main_main()
{
//freopen("r.cpp","r",stdin);
_r(n);
_r(m);
for(int i=1;i<=n;i++)
{
_r(a[i]);
a[i]%=(m+1);
}
for(int i=1,x,y;i<n;i++)
{
_r(x);
_r(y);
add(x,y);
add(y,x);
}
dep[0]=-1;
dfs(1,0);
for(int i=1;i<=n;i++)
{
if(dep[i]&1)
{
change(i,1,a[i]);
}
else
{
change(i,0,a[i]);
}
}
_r(Q);
cnt=0;
for(int i=1,ty,u,v,x;i<=Q;i++)
{
_r(ty);
if(ty==1)
{
_r(x);
x^=cnt;
int t;
if(dep[x]&1)
{
t=query(x,0);
}
else
{
t=query(x,1);
}
if(t)
{
puts("Yes");
++cnt;
}
else
{
puts("No");
}
}
if(ty==2)
{
_r(u);
_r(v);
u^=cnt;
v^=cnt;
v%=(m+1);
if(dep[u]&1)
{
change(u,1,a[u]);
change(u,1,v);
}
else
{
change(u,0,a[u]);
change(u,0,v);
}
a[u]=v;
}
if(ty==3)
{
_r(u);
_r(v);
_r(x);
u^=cnt;
v^=cnt;
x^=cnt;
x%=(m+1);
dep[v]=dep[u]+1;
a[v]=x;
link(v,u);
if(dep[v]&1)
{
change(v,1,a[v]);
}
else
{
change(v,0,a[v]);
}
}
}
return 0;
}
const int main_stack=16;
char my_stack[128<<20];
int main() {
__asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");
__asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp");
main_main();
__asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");
return 0;
}