zoukankan      html  css  js  c++  java
  • [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 }
  • 相关阅读:
    Android Gradle Plugin指南(五)——Build Variants(构建变种版本号)
    文件内容操作篇clearerr fclose fdopen feof fflush fgetc fgets fileno fopen fputc fputs fread freopen fseek ftell fwrite getc getchar gets
    文件操作篇 close creat dup dup2 fcntl flock fsync lseek mkstemp open read sync write
    嵌入式linux应用程序调试方法
    version control system:git/hg/subversion/cvs/clearcase/vss。software configruation management。代码集成CI:Cruisecontrol/hudson/buildbot
    最值得你所关注的10个C语言开源项目
    如何记录linux终端下的操作日志
    CentOS 5.5 虚拟机安装 VirtualBox 客户端增强功能
    sizeof, strlen区别
    C/C++嵌入式开发面试题
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6602252.html
Copyright © 2011-2022 走看看