[博弈 & 字典树合并] BZOJ4730. Alice和Bob又在玩游戏

每棵树单独考虑

对于每个子树,通过枚举删去的点,可以算出剩下的所有树的SG值的异或值的集合,集合的MEX就是这个子树的SG值

用字典树维护所有情况,合并的时候打个标记,然后字典树合并就行了

#include 
#include 
#include 
#include 

using namespace std;

const int N=100010;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}

inline void read(int &x){
  char c=nc(); x=0;
  for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}

int t,n,m,cnt,cnt0,G[N],sg[N],vis[N],rt[N],tag[N*50],size[N*50],ch[N*50][2];
struct edge{
  int t,nx;
}E[N<<1];

inline void addedge(int x,int y){
  E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
  E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}

int Rev(int x){
  int ret=0;
  for(int i=0;i<=20;i++) ret=(ret<<1)|(x>>i&1);
  return ret;
}

inline void Push(int x){
  if(tag[x]&1)
    swap(ch[x][0],ch[x][1]);
  tag[ch[x][0]]^=tag[x]>>1,tag[ch[x][1]]^=tag[x]>>1;
  tag[x]=0;
}

void Up(int x){
  size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}

int Merge(int x,int y){
  if(!x || !y) return x+y;
  Push(x); Push(y);
  ch[x][0]=Merge(ch[x][0],ch[y][0]);
  ch[x][1]=Merge(ch[x][1],ch[y][1]);
  Up(x);
  return x;
}

void Insert(int x,int y,int k=20){
  if(k<0) return Up(x); Push(x);
  if(!ch[x][y>>k&1]) ch[x][y>>k&1]=++cnt0;
  Insert(ch[x][y>>k&1],y,k-1);
  Up(x);
}

int Query(int x){
  int ret=0;
  for(int i=20;~i;i--){
    Push(x);
    if(size[ch[x][0]]==(1<
      ret|=1<
    else
      x=ch[x][0];
  }
  return ret;
}

void dfs(int x,int f){
  rt[x]=++cnt0; size[cnt0]=1; vis[x]=1;
  int sum=0;
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f) dfs(E[i].t,x),sum^=sg[E[i].t];
  for(int i=G[x];i;i=E[i].nx)
    if(E[i].t!=f){
      tag[rt[E[i].t]]^=Rev(sum^sg[E[i].t]);
      int k=Query(rt[E[i].t]);
      rt[x]=Merge(rt[x],rt[E[i].t]);
    }
  Insert(rt[x],sum);
  sg[x]=Query(rt[x]);
}

int main(){
  read(t);
  while(t--){
    read(n); read(m); cnt=cnt0=0; int ans=0;
    memset(ch,0,sizeof(ch));
    memset(tag,0,sizeof(tag));
    memset(size,0,sizeof(size));
    for(int i=1;i<=n;i++) vis[i]=G[i]=0;
    for(int i=1,x,y;i<=m;i++)
      read(x),read(y),addedge(x,y);
    for(int i=1;i<=n;i++)
      if(!vis[i]) dfs(i,0),ans^=sg[i];
    puts(ans?"Alice":"Bob");
  }
  return 0;
}

你可能感兴趣的:(博弈论,字典树)