uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数)
题解时间
考虑如何求出每棵树(子树)的 $ SG $ 。
众所周知一个状态的 $ SG $ 是其后继的 $ mex $ 。
考虑其后继的 $ SG $ 如何求。
对于将 $ y $ 的贡献计算到其父亲 $ x $ 上。
如果删掉 $ x $ ,后继状态是所有儿子的 $ SG $ 异或,
如果删掉 $ y $ 以内的点,则是用 $ y $ 子树内的所有后继状态异或上 $ x $ 子树内 $ y $ 子树外的部分。
这个可以用一棵trie树简单维护,向父亲合并,并求出 $ mex $ 。
#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
template<typename TP>inline void read(TP &tar)
{
TP ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
tar=ret*f;
}
template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
namespace RKK
{
const int N=100011,B=16;
struct sumireko{int to,ne;}e[N<<1];int he[N],ecnt;
void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f],he[f]=ecnt;}
int TAT;
int n,m,sg[N];bool vis[N];
int rt[N],tcnt;
int son[N<<6][2],size[N<<6],tag[N<<6];
void fuckup(int px){size[px]=size[son[px][0]]+size[son[px][1]];}
void fuckdown(int px,int b)
{
if(!tag[px]) return;
if((tag[px]>>b)&1) swap(son[px][0],son[px][1]);
tag[son[px][0]]^=tag[px],tag[son[px][1]]^=tag[px],tag[px]=0;
}
int merge(int px,int py,int b=B)
{
if(!px||!py) return px|py;if(b==-1) return px;
fuckdown(px,b),fuckdown(py,b);
son[px][0]=merge(son[px][0],son[py][0],b-1);
son[px][1]=merge(son[px][1],son[py][1],b-1);
fuckup(px);return px;
}
void insert(int &px,int v,int b=B)
{
if(!px) px=++tcnt,size[px]=1;if(b==-1) return;
fuckdown(px,b);insert(son[px][(v>>b)&1],v,b-1);
fuckup(px);
}
int query(int px,int b=B)
{
if(b==-1) return 0;fuckdown(px,b);
return size[son[px][0]]<(1<<b)?query(son[px][0],b-1):query(son[px][1],b-1)|(1<<b);
}
void dfs(int x,int f=0)
{
vis[x]=1;int tmp=0;
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=f)
dfs(t,x),tmp^=sg[t];
for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=f)
tag[rt[t]]^=(tmp^sg[t]),rt[x]=merge(rt[x],rt[t]);
insert(rt[x],tmp);sg[x]=query(rt[x]);
}
void ESM()
{
read(n,m);for(int i=1,x,y;i<=m;i++) read(x,y),addline(x,y),addline(y,x);
int ans=0;for(int i=1;i<=n;i++)if(!vis[i]) dfs(i),ans^=sg[i];
puts(ans?"Alice":"Bob");
}
void memclr()
{
memset(he+1,0,n*4),ecnt=0;
memset(vis+1,0,n);memset(sg+1,0,n*4);
memset(son+1,0,tcnt*8),memset(size+1,0,tcnt*4),memset(tag+1,0,tcnt*4);
memset(rt+1,0,n*4),tcnt=0;
}
int main()
{
read(TAT);while(TAT--) ESM(),memclr();
return 0;
}
}
int main(){return RKK::main();}