題解 SP11414 【COT3 - Combat on a tree】
阿新 • • 發佈:2020-09-17
發現本題為公平組合遊戲,因此考慮用 \(\text{SG}\) 函式來解決。
設 \(\text{SG}(x)\) 為以 \(x\) 為根的子樹的 \(\text{SG}\) 值。對於點 \(x\),可以列舉其子樹內的每一個白點,刪去該點到 \(x\) 的所有點,然後以 \(x\) 為根的子樹會分裂為一個森林,也就是 \(x\) 狀態可以轉移到這個森林的狀態,一個森林的 \(\text{SG}\) 值為每棵樹的 \(\text{SG}\) 值異或和。\(\text{SG}(x)\) 即為子樹內所有白點刪去後形成的森林對應的 \(\text{SG}\) 值取 \(\text{mex}\)。
考慮用資料結構來優化這個過程,每個節點上都用一個 \(01\ Trie\)
最後再 \(dfs\) 一遍,若一個點的後繼狀態為必敗狀態,則該點可以作為第一步選的點。
#include<bits/stdc++.h> #define maxn 200010 #define maxm 4000010 using namespace std; template<typename T> inline void read(T &x) { x=0;char c=getchar();bool flag=false; while(!isdigit(c)){if(c=='-')flag=true;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} if(flag)x=-x; } int n,tot,cnt; int c[maxn],sg[maxn],ans[maxn],rt[maxn],ch[maxm][2],tag[maxm]; bool cov[maxm]; struct edge { int to,nxt; }e[maxn]; int head[maxn],edge_cnt; void add(int from,int to) { e[++edge_cnt]={to,head[from]},head[from]=edge_cnt; } void pushtag(int p,int k,int x) { if(k==-1) return; if(x>>k&1) swap(ch[p][0],ch[p][1]); tag[p]^=x; } void pushdown(int p,int k) { if(!tag[p]) return; pushtag(ch[p][0],k-1,tag[p]),pushtag(ch[p][1],k-1,tag[p]),tag[p]=0; } void insert(int &p,int k,int x) { if(!p) p=++tot; if(k==-1) { cov[p]=true; return; } insert(ch[p][x>>k&1],k-1,x); cov[p]=cov[ch[p][0]]&cov[ch[p][1]]; } int merge(int x,int y,int k) { if(!x||!y) return x+y; if(k==-1) { cov[x]|=cov[y]; return x; } pushdown(x,k),pushdown(y,k); ch[x][0]=merge(ch[x][0],ch[y][0],k-1); ch[x][1]=merge(ch[x][1],ch[y][1],k-1); cov[x]=cov[ch[x][0]]&cov[ch[x][1]]; return x; } int mex(int p,int k) { if(!p||k==-1) return 0; pushdown(p,k); if(cov[ch[p][0]]) return (1<<k)|mex(ch[p][1],k-1); return mex(ch[p][0],k-1); } void dfs_get(int x,int fa) { int v=0; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa) continue; dfs_get(y,x),v^=sg[y]; } for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa) continue; pushtag(rt[y],20,v^sg[y]); rt[x]=merge(rt[x],rt[y],20); } if(!c[x]) insert(rt[x],20,v); sg[x]=mex(rt[x],20); } void dfs_ans(int x,int fa,int v) { for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa) continue; v^=sg[y]; } if(!v&&!c[x]) ans[++cnt]=x; for(int i=head[x];i;i=e[i].nxt) { int y=e[i].to; if(y==fa) continue; dfs_ans(y,x,v^sg[y]); } } int main() { read(n); for(int i=1;i<=n;++i) read(c[i]); for(int i=1;i<n;++i) { int x,y; read(x),read(y); add(x,y),add(y,x); } dfs_get(1,0); if(!sg[1]) puts("-1"); else { dfs_ans(1,0,0),sort(ans+1,ans+cnt+1); for(int i=1;i<=cnt;++i) printf("%d ",ans[i]); } return 0; }