题目链接
- 【SG函数】使用01Trie可以支持动态查询当前集合的mex值
- 如果删除操作发生在根,那后继局面的SG函数值可以直接通过SG定理求出
- 如果删除操作发生在子树,那根据SG定理,后继局面的SG函数值需要在原来的基础上统一异或上一个数
#include <bits/stdc++.h>
using namespace std;
vector<int>a[100005];
bool v[100005];
int tot,t[100000*18+5][2],s[100000*18+5],bj[100000*18+5];
int sg[100005];
void pushdown(int p,int k)
{
if((bj[p]>>k)&1)
{
swap(t[t[p][0]][0],t[t[p][0]][1]);
swap(t[t[p][1]][0],t[t[p][1]][1]);
}
bj[t[p][0]]^=bj[p];
bj[t[p][1]]^=bj[p];
bj[p]=0;
}
int merge(int p,int q,int x,int k)
{
if(k==-2)
{
return 0;
}
if(!p&&!q)
{
return 0;
}
if(!p)
{
if((x>>k)&1)
{
swap(t[q][0],t[q][1]);
}
bj[q]^=x;
return q;
}
if(!q)
{
return p;
}
if(k>=1)
{
pushdown(p,k-1);
pushdown(q,k-1);
}
t[p][0]=merge(t[p][0],t[q][(x>>k)&1],x,k-1);
t[p][1]=merge(t[p][1],t[q][((x>>k)&1)^1],x,k-1);
s[p]=s[t[p][0]]+s[t[p][1]]+(k==-1);
return p;
}
int ask(int p,int k)
{
if(p==0||k==-1)
{
return 0;
}
if(s[t[p][0]]==(1<<k))
{
return (1<<k)+ask(t[p][1],k-1);
}
else
{
return ask(t[p][0],k-1);
}
}
void insert(int p,int x,int k)
{
if(k==-1)
{
s[p]=1;
return;
}
if(!t[p][(x>>k)&1])
{
t[p][(x>>k)&1]=++tot;
t[tot][0]=t[tot][1]=s[tot]=bj[tot]=0;
}
insert(t[p][(x>>k)&1],x,k-1);
s[p]=s[t[p][0]]+s[t[p][1]];
}
void dfs(int n1,int fa)
{
v[n1]=true;
int sum=0;
for(int i=0;i<a[n1].size();i++)
{
if(a[n1][i]!=fa)
{
dfs(a[n1][i],n1);
sum=sum^sg[a[n1][i]];
}
}
for(int i=0;i<a[n1].size();i++)
{
if(a[n1][i]!=fa)
{
sum=sum^sg[a[n1][i]];
merge(n1,a[n1][i],sum,16);
sum=sum^sg[a[n1][i]];
}
}
insert(n1,sum,16);
sg[n1]=ask(n1,16);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin>>T;
while(T--)
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
v[i]=false;
a[i].clear();
t[i][0]=t[i][1]=s[i]=bj[i]=0;
sg[i]=0;
}
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
int ans=0;
tot=n;
for(int i=1;i<=n;i++)
{
if(!v[i])
{
dfs(i,0);
ans=ans^sg[i];
}
}
if(ans==0)
{
cout<<"Bob\n";
}
else
{
cout<<"Alice\n";
}
}
return 0;
}