BZOJ 4730: Alice和Bob又在玩游戏

Description

Alice和Bob在玩游戏。有n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最
小的点。Alice和Bob轮流操作,每回合选择一个没有被删除的节点x,将x及其所有祖先全部删除,不能操作的人输

Solution

博弈+Trie树合并。

可以暴力算出SG函数,就是自底向上求SG函数,再自上而下的求当前点的SG函数。

求当前点的时候就是子节点的SG集合异或异或其他子节点的异或和。

这其实就是Trie树,然后就是合并的问题了。

Code

/**************************************************************
    Problem: 4730
    User: BeiYu
    Language: C++
    Result: Accepted
    Time:2940 ms
    Memory:49552 kb
****************************************************************/
 
#include <bits/stdc++.h>
using namespace std;
 
#define lc(o) ch[o][0]
#define rc(o) ch[o][1]
 
typedef long long LL;
const int N = (1<<19)+50;
 
inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
 
 
int T,n,m;
vector<int> g[N];
int f[N],sg[N];
int rt[N],cnt,ch[N<<2][2],rev[N<<2],sz[N<<2];
 
int NewNode() { ++cnt;lc(cnt)=rc(cnt)=sz[cnt]=rev[cnt]=0;return cnt; }
int find(int x) { return f[x]==x?x:f[x]=find(f[x]); }
namespace Trie {
    void insert(int o,int v,int k) {
        sz[o]++;
        if(!k) return;
        if(v&k) {
            if(!rc(o)) rc(o)=NewNode();
            insert(rc(o),v,k>>1);
        } else {
            if(!lc(o)) lc(o)=NewNode();
            insert(lc(o),v,k>>1);
        }
    }
    void update(int o) { sz[o]=sz[lc(o)]+sz[rc(o)]; }
    void push(int o,int k) {
        if(rev[o]&k) swap(lc(o),rc(o));
        if(lc(o)) rev[lc(o)]^=rev[o];
        if(rc(o)) rev[rc(o)]^=rev[o];
        rev[o]=0;
    }
    int merge(int u,int v,int k) {
        if(!u || !v) return u+v;
        if(k==1) return sz[u]>sz[v]?u:v;
        push(u,k>>1),push(v,k>>1);
        lc(u)=merge(lc(u),lc(v),k>>1);
        rc(u)=merge(rc(u),rc(v),k>>1);
        update(u);
        return u;
    }
    int mex(int o,int k) {
        if(!o || !k) return 0;
        push(o,k);
        if(sz[lc(o)]<(k>>1)) return mex(lc(o),k>>1);
        else return mex(rc(o),k>>1)|(k>>1);
    }
}
using namespace Trie;
 
int SG(int u,int fa) {
    int t=0;rt[u]=NewNode();
    for(int i=0;i<(int)g[u].size();i++) if(g[u][i]!=fa) t^=SG(g[u][i],u);
    insert(rt[u],t,1<<15);
    for(int i=0,v;i<(int)g[u].size();i++) if((v=g[u][i])!=fa) 
        rev[rt[v]]^=t^sg[v],rt[u]=merge(rt[u],rt[v],1<<16);
    return sg[u]=mex(rt[u],1<<16);
}
void clear() {
    cnt=0;
    for(int i=1;i<=n;i++) f[i]=i,rt[i]=0,g[i].clear();
}
int main() {
    for(T=in();T--;) {
        n=in(),m=in();
        clear();
        for(int i=1;i<=m;i++) {
            int x=in(),y=in();
            g[x].push_back(y),g[y].push_back(x);
            int f1=find(x),f2=find(y);
            if(f1>f2) swap(f1,f2);
            f[f2]=f1;
        }
        int ans=0;
        for(int i=1;i<=n;i++) if(find(i)==i) ans^=SG(i,i);
        if(ans) puts("Alice");else puts("Bob");
    }return 0;
}

  

原文地址:https://www.cnblogs.com/beiyuoi/p/6549207.html