链接
题解
先考虑
O
(
n
2
)
O(n^2)
O(n2)的做法
对于一个子树,如果我们可以知道他可以凑出哪些数
那么对于一个儿子
s
o
n
j
son_j
sonj并到父亲的时候,就要异或所有别的儿子的SG值
如果暴力维护和vector什么的,就可以
n
2
n^2
n2了
考虑怎么优化这个过程
一开始想维护线段树,但是似乎没什么办法资瓷合并
虽然现在想一想,如果把线段树的范围变成
[
0
,
2
i
]
[0,2^i]
[0,2i]就可以了
也可以使用字典树
和线段树一样,都是把我能弄出来的数查到里面
那么打lazy的时候,就相当于是把某些位的左右儿子取反
显然可以实现
然后求sg的时候,就再字典树上面二分就可以了
CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
const int N=100005;
int T;
int n,m;
vector<int> vec[N];
bool vis[N];
int sg[N];
int bin[21];
int rt[N],s1[N*22],s2[N*22],lzy[N*22],c[N*22];
int num=0;
void Push_down (int now,int dep)
{
if (lzy[now]&bin[dep-1]) swap(s1[now],s2[now]);
lzy[s1[now]]^=lzy[now];lzy[s2[now]]^=lzy[now];
lzy[now]=0;
}
void Merge (int &rt1,int rt2,int dep)
{
if (rt1==0) {rt1=rt2;return ;}
if (rt2==0) return ;
Push_down(rt1,dep); Push_down(rt2,dep);
Merge(s1[rt1],s1[rt2],dep-1);Merge(s2[rt1],s2[rt2],dep-1);
c[rt1]=c[s1[rt1]]+c[s2[rt1]]+(dep==0);
}
void insert (int &now,int x,int dep)
{
if (now==0) now=++num;c[now]++;
if (dep<=0) return ;
if (x&bin[dep-1]) insert(s2[now],x,dep-1);
else insert(s1[now],x,dep-1);
}
void dfs (int x,int fa)
{
vis[x]=true;
int siz=vec[x].size();int t=0;
for (int u=0;u<siz;u++)
{
int y=vec[x][u];
if (y==fa) continue;
dfs(y,x);
t^=sg[y];
}
insert(rt[x],t,21);
for (int u=0;u<siz;u++)
{
int y=vec[x][u];
if (y==fa) continue;
lzy[rt[y]]^=(t^sg[y]);
Merge(rt[x],rt[y],21);
}
int now=rt[x];sg[x]=0;
for (int u=21;u>0;u--)
{
//printf("%d %d %d %d %d\n",now,c[now],u,s1[now],c[s1[now]]);
if (c[s1[now]]<bin[u-1]) now=s1[now];
else {sg[x]|=bin[u-1];now=s2[now];}
}
// printf("%d %d\n",x,sg[x]);
}
int main()
{
bin[0]=1;for (int u=1;u<=20;u++) bin[u]=(bin[u-1]<<1);
scanf("%d",&T);
while (T--)
{
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++) vis[u]=false,vec[u].clear(),rt[u]=0;
for (int u=1;u<=m;u++)
{
int x,y;
scanf("%d%d",&x,&y);
vec[x].push_back(y);vec[y].push_back(x);
}
int ans=0;
for (int u=1;u<=n;u++) if (vis[u]==false) {dfs(u,0);ans^=sg[u];}
for (int u=0;u<=num;u++) s1[u]=s2[u]=c[u]=lzy[u]=0;num=0;
if (ans!=0) printf("Alice\n");
else printf("Bob\n");
}
return 0;
}