Description
Alice和Bob在玩游戏。有n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最
小的点。Alice和Bob轮流操作,每回合选择一个没有被删除的节点x,将x及其所有祖先全部删除,不能操作的人输
。
Solution
博弈+Trie树合并。
可以暴力算出SG函数,就是自底向上求SG函数,再自上而下的求当前点的SG函数。
求当前点的时候就是子节点的SG集合异或异或其他子节点的异或和。
这其实就是Trie树,然后就是合并的问题了。
Code
/************************************************************** Problem: 4730 User: BeiYu Language: C++ Result: Accepted Time:2940 ms Memory:49552 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; #define lc(o) ch[o][0] #define rc(o) ch[o][1] typedef long long LL; const int N = (1<<19)+50; inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; } int T,n,m; vector<int> g[N]; int f[N],sg[N]; int rt[N],cnt,ch[N<<2][2],rev[N<<2],sz[N<<2]; int NewNode() { ++cnt;lc(cnt)=rc(cnt)=sz[cnt]=rev[cnt]=0;return cnt; } int find(int x) { return f[x]==x?x:f[x]=find(f[x]); } namespace Trie { void insert(int o,int v,int k) { sz[o]++; if(!k) return; if(v&k) { if(!rc(o)) rc(o)=NewNode(); insert(rc(o),v,k>>1); } else { if(!lc(o)) lc(o)=NewNode(); insert(lc(o),v,k>>1); } } void update(int o) { sz[o]=sz[lc(o)]+sz[rc(o)]; } void push(int o,int k) { if(rev[o]&k) swap(lc(o),rc(o)); if(lc(o)) rev[lc(o)]^=rev[o]; if(rc(o)) rev[rc(o)]^=rev[o]; rev[o]=0; } int merge(int u,int v,int k) { if(!u || !v) return u+v; if(k==1) return sz[u]>sz[v]?u:v; push(u,k>>1),push(v,k>>1); lc(u)=merge(lc(u),lc(v),k>>1); rc(u)=merge(rc(u),rc(v),k>>1); update(u); return u; } int mex(int o,int k) { if(!o || !k) return 0; push(o,k); if(sz[lc(o)]<(k>>1)) return mex(lc(o),k>>1); else return mex(rc(o),k>>1)|(k>>1); } } using namespace Trie; int SG(int u,int fa) { int t=0;rt[u]=NewNode(); for(int i=0;i<(int)g[u].size();i++) if(g[u][i]!=fa) t^=SG(g[u][i],u); insert(rt[u],t,1<<15); for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i])!=fa) rev[rt[v]]^=t^sg[v],rt[u]=merge(rt[u],rt[v],1<<16); return sg[u]=mex(rt[u],1<<16); } void clear() { cnt=0; for(int i=1;i<=n;i++) f[i]=i,rt[i]=0,g[i].clear(); } int main() { for(T=in();T--;) { n=in(),m=in(); clear(); for(int i=1;i<=m;i++) { int x=in(),y=in(); g[x].push_back(y),g[y].push_back(x); int f1=find(x),f2=find(y); if(f1>f2) swap(f1,f2); f[f2]=f1; } int ans=0; for(int i=1;i<=n;i++) if(find(i)==i) ans^=SG(i,i); if(ans) puts("Alice");else puts("Bob"); }return 0; }