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 }
  • 相关阅读:
    c#操作Excel时,抛出异常:“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”
    设计模式(二)(Factory method)工厂方法设计模式
    设计模式(一)Singlton
    oracle中merge的用法,以及各版本的区别 Create
    rowid去重(删除表的重复记录)
    Oracle 12C 新特性之 恢复表
    Oracle 12C 新特性之 sqlplus查看History命令
    Oracle 12C 新特性之 PDB热克隆(本地克隆、远端异机克隆)
    Oracle 12C 新特性之 db默认字符集AL32UTF8、PDB支持不同字符集
    Oracle 12C 新特性之表分区部分索引(Partial Indexes)
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6602252.html
Copyright © 2011-2022 走看看