题意:俩智障又在玩游戏。规则如下:

给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全部删除,不能操作者输。判断先手胜负。

题解:比较神的一道题。

我们现在要解决的问题是怎么求解一棵子树的SG值,首先把根删掉的情况考虑,这很好办,直接把子树的sg异或起来就好,关键是如果删除点在子树里怎么办。

这里用到了一个巧妙的东西,trie。怎么会用这个呢?因为删除子树里的节点就相当于是子树里这种对应的情况再异或上外边子树的sg。但是我们不可能用一般的方法来存一棵子树里所有的sg。这个时候trie应运而生。我们处理子树之后,把它合并上来,就能得到当前节点的所有拓展局面的sg了。这里注意,合并子树前要先在子树上打一个tag(因为它是要异或上外面所有子树sg的)。

算法很清晰了,dfs下去,合并上来。这里的trie还要打tag。所有细节就这么多。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define N 100005
 5  
 6 inline LL read(){
 7        LL x=0,f=1; char a=getchar();
 8        while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
 9        while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
10        return x*f;
11 }
12  
13 int n,m,T,bin[25],head[N],cnt,id,tag[N*20],rt[N],ls[N*20],rs[N*20],sg[N],sz[N*20];
14 bool vis[N];
15  
16 struct edges{
17     int to,next;
18 }e[2*N];
19  
20 inline void insert(){
21     int u=read(),v=read();
22     e[++cnt]=(edges){v,head[u]};head[u]=cnt;
23     e[++cnt]=(edges){u,head[v]};head[v]=cnt;
24 }
25  
26 inline void init(){
27     bin[0]=1; for(int i=1;i<=19;i++) bin[i]=bin[i-1]<<1;
28 }
29  
30 inline void pushdown(int k,int level){
31     if(!tag[k]) return;
32     if(bin[level-1]&tag[k]) swap(ls[k],rs[k]);
33     tag[ls[k]]^=tag[k]; tag[rs[k]]^=tag[k];
34     tag[k]=0;
35 }
36  
37 inline void reset(){
38     for(int i=1;i<=n;i++) head[i]=sg[i]=rt[i]=0,vis[i]=0;
39     for(int i=1;i<=id;i++) tag[i]=ls[i]=rs[i]=sz[i]=0;
40     cnt=1; id=0;
41 }
42  
43 void ins(int& k,int x,int level){ // 0 is on the left
44     k=++id; sz[k]=1;
45     if(!level) return;
46     if(x&bin[level-1]) ins(rs[k],x,level-1);
47     else ins(ls[k],x,level-1);
48 }
49  
50 int merge(int x,int y,int level){
51     if(!x || !y) return x|y;
52     pushdown(x,level); pushdown(y,level);
53     ls[x]=merge(ls[x],ls[y],level-1); rs[x]=merge(rs[x],rs[y],level-1);
54     sz[x]=sz[ls[x]]+sz[rs[x]]+(level?0:1);
55     return x;
56 }
57  
58 void dfs(int x,int fa){
59     vis[x]=1; int t=0;
60     for(int i=head[x];i;i=e[i].next){
61         if(fa==e[i].to) continue;
62         dfs(e[i].to,x); t^=sg[e[i].to];
63     }
64     ins(rt[x],t,19);
65     for(int i=head[x];i;i=e[i].next){
66         if(fa==e[i].to) continue;
67         tag[rt[e[i].to]]^=t^sg[e[i].to];
68         rt[x]=merge(rt[x],rt[e[i].to],19);
69     }
70     for(int now=rt[x],i=19;i;i--){ // i is the i th digit int binary system
71         pushdown(now,i);
72         if(sz[ls[now]]<bin[i-1]) now=ls[now];
73         else sg[x]|=bin[i-1],now=rs[now];
74     }
75 }
76  
77 inline void solve(){
78     n=read(); m=read(); int ans=0;
79     for(int i=1;i<=m;i++) insert();
80     for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0),ans^=sg[i];
81     puts(ans?"Alice":"Bob");
82 }
83  
84 int main(){
85     init(); T=read();
86     while(T--){
87         solve();
88         reset();
89     }
90     return 0;
91 }