luogu P6665 [清華集訓2016] Alice 和 Bob 又在玩遊戲
阿新 • • 發佈:2022-03-20
題面傳送門
首先你必須瞭解的是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(); }