首页 > 代码库 > [BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏
[BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏
题意:俩智障又在玩游戏。规则如下:
给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全部删除,不能操作者输。判断先手胜负。
题解:比较神的一道题。
我们现在要解决的问题是怎么求解一棵子树的SG值,首先把根删掉的情况考虑,这很好办,直接把子树的sg异或起来就好,关键是如果删除点在子树里怎么办。
这里用到了一个巧妙的东西,trie。怎么会用这个呢?因为删除子树里的节点就相当于是子树里这种对应的情况再异或上外边子树的sg。但是我们不可能用一般的方法来存一棵子树里所有的sg。这个时候trie应运而生。我们处理子树之后,把它合并上来,就能得到当前节点的所有拓展局面的sg了。这里注意,合并子树前要先在子树上打一个tag(因为它是要异或上外面所有子树sg的)。
算法很清晰了,dfs下去,合并上来。这里的trie还要打tag。所有细节就这么多。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define N 100005 5 6 inline LL read(){ 7 LL x=0,f=1; char a=getchar(); 8 while(a<‘0‘ || a>‘9‘) {if(a==‘-‘) f=-1; a=getchar();} 9 while(a>=‘0‘ && a<=‘9‘) x=x*10+a-‘0‘,a=getchar(); 10 return x*f; 11 } 12 13 int n,m,T,bin[25],head[N],cnt,id,tag[N*20],rt[N],ls[N*20],rs[N*20],sg[N],sz[N*20]; 14 bool vis[N]; 15 16 struct edges{ 17 int to,next; 18 }e[2*N]; 19 20 inline void insert(){ 21 int u=read(),v=read(); 22 e[++cnt]=(edges){v,head[u]};head[u]=cnt; 23 e[++cnt]=(edges){u,head[v]};head[v]=cnt; 24 } 25 26 inline void init(){ 27 bin[0]=1; for(int i=1;i<=19;i++) bin[i]=bin[i-1]<<1; 28 } 29 30 inline void pushdown(int k,int level){ 31 if(!tag[k]) return; 32 if(bin[level-1]&tag[k]) swap(ls[k],rs[k]); 33 tag[ls[k]]^=tag[k]; tag[rs[k]]^=tag[k]; 34 tag[k]=0; 35 } 36 37 inline void reset(){ 38 for(int i=1;i<=n;i++) head[i]=sg[i]=rt[i]=0,vis[i]=0; 39 for(int i=1;i<=id;i++) tag[i]=ls[i]=rs[i]=sz[i]=0; 40 cnt=1; id=0; 41 } 42 43 void ins(int& k,int x,int level){ // 0 is on the left 44 k=++id; sz[k]=1; 45 if(!level) return; 46 if(x&bin[level-1]) ins(rs[k],x,level-1); 47 else ins(ls[k],x,level-1); 48 } 49 50 int merge(int x,int y,int level){ 51 if(!x || !y) return x|y; 52 pushdown(x,level); pushdown(y,level); 53 ls[x]=merge(ls[x],ls[y],level-1); rs[x]=merge(rs[x],rs[y],level-1); 54 sz[x]=sz[ls[x]]+sz[rs[x]]+(level?0:1); 55 return x; 56 } 57 58 void dfs(int x,int fa){ 59 vis[x]=1; int t=0; 60 for(int i=head[x];i;i=e[i].next){ 61 if(fa==e[i].to) continue; 62 dfs(e[i].to,x); t^=sg[e[i].to]; 63 } 64 ins(rt[x],t,19); 65 for(int i=head[x];i;i=e[i].next){ 66 if(fa==e[i].to) continue; 67 tag[rt[e[i].to]]^=t^sg[e[i].to]; 68 rt[x]=merge(rt[x],rt[e[i].to],19); 69 } 70 for(int now=rt[x],i=19;i;i--){ // i is the i th digit int binary system 71 pushdown(now,i); 72 if(sz[ls[now]]<bin[i-1]) now=ls[now]; 73 else sg[x]|=bin[i-1],now=rs[now]; 74 } 75 } 76 77 inline void solve(){ 78 n=read(); m=read(); int ans=0; 79 for(int i=1;i<=m;i++) insert(); 80 for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0),ans^=sg[i]; 81 puts(ans?"Alice":"Bob"); 82 } 83 84 int main(){ 85 init(); T=read(); 86 while(T--){ 87 solve(); 88 reset(); 89 } 90 return 0; 91 }
[BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。