1. 程式人生 > 其它 >luogu P6665 [清華集訓2016] Alice 和 Bob 又在玩遊戲

luogu P6665 [清華集訓2016] Alice 和 Bob 又在玩遊戲

題面傳送門
首先你必須瞭解的是SG定理,設\(f_S\)\(S\)狀態對應的SG值,則設\(S\)可以到達的狀態為\(T\),則\(f_S=\operatorname{mex}{f_T}\)
如果\(S\)能被劃分成若干個互不影響的狀態,記為\(S1,S2,\dots,S_k\),則\(f_i\)為所有\(f_{S_j}\)的異或和。
如果\(f_i\)\(0\)則先手必敗,反之必勝。
那麼這個題就變成在子樹內列舉一個點,然後把這個點到根的路徑全刪了,剩下的子樹的SG值異或起來,最後求mex。
然後發現這個東西其實可以合併子樹,只要全域性異或上一個東西就好了,Trie隨便維護。
時間複雜度\(O(n\log n)\)


code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (100000+5)
#define M (100000)
#define mod 998244353
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int x,y,T,n,m,Ans,Ro[N],dp[N],vis[N];vector<int> S[N];
namespace Trie{
	int cnt,F[N*20],L[N*20],R[N*20],Fl[N*20],Val[N*20];I void Up(int now){F[now]=F[L[now]]+F[R[now]];}
	I void PF(int now,int d,int w){now&&(Fl[now]^=w,w>>d&1&&(swap(L[now],R[now]),0));}I void P(int now,int d){Fl[now]&&(PF(L[now],d-1,Fl[now]),PF(R[now],d-1,Fl[now]),Fl[now]=0);}
	I void Ins(int x,int &now,int d=18){!now&&(now=++cnt);if(d==-1){Val[now]++;F[now]=1;return;}P(now,d);x>>d&1?Ins(x,R[now],d-1):Ins(x,L[now],d-1);Up(now);}
	I int ME(int x,int y,int d=18){if(!x||!y) return x|y;if(d==-1){Val[x]+=Val[y];return x;}P(x,d);P(y,d);L[x]=ME(L[x],L[y],d-1);R[x]=ME(R[x],R[y],d-1);Up(x);return x;}
	I int Qry(int now,int d=18){if(d==-1) return 0;P(now,d);return F[L[now]]^(1<<d)?Qry(L[now],d-1):Qry(R[now],d-1)|(1<<d);}
}
I void calc(int x,int La){vis[x]=1;RI Ns=0;for(RI i:S[x]) i^La&&(calc(i,x),Ns^=dp[i]);Trie::Ins(Ns,Ro[x]);for(RI i:S[x]) i^La&&(Trie::PF(Ro[i],18,Ns^dp[i]),Ro[x]=Trie::ME(Ro[x],Ro[i]));dp[x]=Trie::Qry(Ro[x]);}
I void Solve(){
	RI i;scanf("%d%d",&n,&m);for(i=1;i<=m;i++) scanf("%d%d",&x,&y),S[x].PB(y),S[y].PB(x);Ans=0;for(i=1;i<=n;i++) !vis[i]&&(calc(i,0),Ans^=dp[i]);
	puts(Ans?"Alice":"Bob");for(i=1;i<=n;i++) vis[i]=dp[i]=Ro[i]=0,S[i].clear();for(i=1;i<=Trie::cnt;i++) Trie::F[i]=Trie::Fl[i]=Trie::L[i]=Trie::R[i]=0;Trie::cnt=0;
}
int main(){
	freopen("1.in","r",stdin);
	scanf("%d",&T);while(T--)Solve();
}