• [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 }
  • 相关阅读:
    jmeter响应结果乱码问题
    JMeter 脚本请求错误 HTTP Status 415 的解决
    使用fiddler进行genymotion安卓虚拟机手机抓包
    Android模拟器Genymotion安装使用教程详解
    java基础-数组
    Qt类继承图
    Linux-磁盘管理小结
    User and User Groups in Linux
    Qt5.3编译错误——call of overloaded ‘max(int int)’is ambiguous
    i++ and ++i efficiency
  • 原文地址:https://www.cnblogs.com/enigma-aw/p/6602252.html
Copyright © 2020-2023  润新知