题解:P10662 BZOJ4202 石子游戏
Solution
一眼丁真,鉴定为:不会写 Splay。
考虑本题本质上是一个阶梯博弈 + 巴什博弈。
那么我们认为一个节点的实际石子个数为
在动态维护 LCT 的过程中,如果新增一个节点或者修改一个节点,把它到根这条路径上所有点都异或上新增的值。
每个点要开两个值,分别维护深度为奇数的点的异或和与深度为偶数的点的异或和。
#include<bits/stdc++.h>
#define ffor(i,a,b) for(int i=(a);i<=(b);i++)
#define roff(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
const int MAXN=1e5+10;
int n,m,q,a[MAXN],dep[MAXN],lstans;
vector<int> G[MAXN];
struct Node {int s[2],fa,x0,x1;}t[MAXN];
struct Tag {int tg0,tg1,flp;}tag[MAXN];
void assign(int u,Tag tg) {
if(tg.flp) swap(t[u].s[0],t[u].s[1]),tag[u].flp^=1;
return t[u].x0^=tg.tg0,t[u].x1^=tg.tg1,tag[u].tg0^=tg.tg0,tag[u].tg1^=tg.tg1,void();
}
void push_down(int u) {return assign(t[u].s[0],tag[u]),assign(t[u].s[1],tag[u]),tag[u]={0,0,0},void();}
void push_up(int u) {return ;}
int is_root(int u) {return u!=t[t[u].fa].s[0]&&u!=t[t[u].fa].s[1];}
int get(int u) {return u==t[t[u].fa].s[1];}
void rotate(int u) {
int fa=t[u].fa,s=get(u),op=get(fa);
if(!is_root(fa)) t[t[fa].fa].s[op]=u;t[u].fa=t[fa].fa;
t[t[u].s[s^1]].fa=fa,t[fa].fa=u,t[fa].s[s]=t[u].s[s^1],t[u].s[s^1]=fa;
return ;
}
void PUSH_DOWN(int u) {if(!is_root(u)) PUSH_DOWN(t[u].fa);return push_down(u),void();}
void splay(int u) {PUSH_DOWN(u);for(int f=t[u].fa;f=t[u].fa,!is_root(u);rotate(u)) if(!is_root(f)) rotate(get(u)==get(f)?f:u);return ;}
int access(int u) {int lst=0;while(u) splay(u),t[u].s[1]=lst,lst=u,u=t[u].fa;return lst;}
void make_root(int u) {return assign(access(u),{0,0,1}),void();}
void link(int u,int v) {return make_root(u),splay(u),t[u].s[1]=v,t[v].fa=u,void();}
void dfs(int u,int f) {
dep[u]=dep[f]^1;
if(f) {
int rt;
link(f,u),make_root(1),rt=access(u);
if(dep[u]) assign(rt,{0,a[u],0});
else assign(rt,{a[u],0,0});
}
for(auto v:G[u]) if(v!=f) dfs(v,u);
return ;
}
int main() {
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin>>n>>m;
ffor(i,1,n) cin>>a[i],a[i]%=m+1;
ffor(i,1,n-1) {int u,v;cin>>u>>v,G[u].push_back(v),G[v].push_back(u);}
dfs(1,0);
cin>>q;
while(q--) {
int op;
cin>>op;
if(op==1) {
int u,val;
cin>>u,u^=lstans;
PUSH_DOWN(u);
if(dep[u]) val=t[u].x0;
else val=t[u].x1;
if(val) cout<<"Yes\n",lstans++;
else cout<<"No\n";
}
if(op==2) {
int x,y,rt;
cin>>x>>y,x^=lstans,y^=lstans,y%=m+1;
make_root(1),rt=access(x);
if(dep[x]) assign(rt,{0,a[x]^y,0});
else assign(rt,{a[x]^y,0,0});
a[x]=y;
}
if(op==3) {
int u,v,x,rt;
cin>>u>>v>>x,u^=lstans,v^=lstans,x^=lstans;
dep[v]=dep[u]^1,a[v]=x%(m+1);
link(u,v),make_root(1),rt=access(v);
if(dep[v]) assign(rt,{0,a[v],0});
else assign(rt,{a[v],0,0});
}
}
return 0;
}