【bzoj4730】 Alice和Bob又在玩游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=4730 (题目链接)
题意
给出一个森林,两个人轮流操作,每次把一个节点以及它的祖先全部抹去,无节点可以抹去是算输,问是否存在先手必胜策略。
Solution
trie树合并,其实就是线段树合并。
bzoj4134的简单版:http://blog.csdn.net/werkeytom_ftd/article/details/50958988
细节
二进制小心写错
代码
// bzoj4730 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<queue> #define LL long long #define inf (1ll<<60) #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=1000010; int head[maxn],vis[maxn],SG[maxn],rt[maxn],n,m,sz,cnt,bin[30]; struct edge {int to,next;}e[maxn<<1]; struct node { int ls,rs,tag,size; void Init() {ls=rs=tag=size=0;} }tr[maxn<<2]; void link(int u,int v) { e[++cnt]=(edge){v,head[u]};head[u]=cnt; e[++cnt]=(edge){u,head[v]};head[v]=cnt; } void pushdown(int k,int x) { if (tr[k].tag&bin[x-1]) swap(tr[k].ls,tr[k].rs); tr[tr[k].ls].tag^=tr[k].tag; tr[tr[k].rs].tag^=tr[k].tag; tr[k].tag=0; } void insert(int &k,int x,int y) { if (!k) k=++sz;tr[k].Init(); tr[k].size=1;if (!y) return; x&bin[y-1] ? insert(tr[k].rs,x,y-1) : insert(tr[k].ls,x,y-1); } int merge(int x,int y,int k) { if (!x || !y) return x|y; pushdown(x,k);pushdown(y,k); tr[x].ls=merge(tr[x].ls,tr[y].ls,k-1); tr[x].rs=merge(tr[x].rs,tr[y].rs,k-1); tr[x].size=tr[tr[x].ls].size+tr[tr[x].rs].size+(k==0); return x; } void dfs(int x,int fa) { int t=0;vis[x]=1; //t表示儿子的SG异或和 for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) { dfs(e[i].to,x); t^=SG[e[i].to]; } insert(rt[x],t,20); //此时插入的是删除x所得到的后继状态的SG值 for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) { tr[rt[e[i].to]].tag=t^SG[e[i].to]; //异或上除e[i].to以外其它儿子节点子树的SG rt[x]=merge(rt[x],rt[e[i].to],20); } for (int i=20,p=rt[x];i;i--) { pushdown(p,i); if (tr[tr[p].ls].size<bin[i-1]) p=tr[p].ls; else SG[x]|=bin[i-1],p=tr[p].rs; } } int main() { bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1; int T;scanf("%d",&T); while (T--) { sz=0;cnt=0; for (int i=1;i<=n;i++) vis[i]=rt[i]=SG[i]=head[i]=0; scanf("%d%d",&n,&m); for (int u,v,i=1;i<=m;i++) { scanf("%d%d",&u,&v); link(u,v); } int ans=0; for (int i=1;i<=n;i++) if (!vis[i]) dfs(i,0),ans^=SG[i]; puts(ans ? "Alice" : "Bob"); } return 0; }
This passage is made by MashiroSky.