zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    css03层次选择器
    css02基本选择器
    Distance Between Points
    CloseHandle(IntPtr handle)抛异常
    关于win7上内存占用较大的说明
    C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试(续)
    五种开源协议的比较(BSD_Apache_GPL_LGPL_MIT)
    C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试
    Opencv不用每次创建项目配置vs2010 vc++目录 库目录等项
    矩阵运算
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6549207.html
Copyright © 2011-2022 走看看