zoukankan      html  css  js  c++  java
  • uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数)

    uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数)

    uoj

    题解时间

    考虑如何求出每棵树(子树)的 $ SG $ 。

    众所周知一个状态的 $ SG $ 是其后继的 $ mex $ 。

    考虑其后继的 $ SG $ 如何求。

    对于将 $ y $ 的贡献计算到其父亲 $ x $ 上。

    如果删掉 $ x $ ,后继状态是所有儿子的 $ SG $ 异或,

    如果删掉 $ y $ 以内的点,则是用 $ y $ 子树内的所有后继状态异或上 $ x $ 子树内 $ y $ 子树外的部分。

    这个可以用一棵trie树简单维护,向父亲合并,并求出 $ mex $ 。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long lint;
    struct pat{int x,y;pat(int x=0,int y=0):x(x),y(y){}bool operator<(const pat &p)const{return x==p.x?y<p.y:x<p.x;}};
    template<typename TP>inline void read(TP &tar)
    {
    	TP ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
    	tar=ret*f;
    }
    template<typename TP,typename... Args>inline void read(TP& t,Args&... args){read(t),read(args...);}
    namespace RKK
    {
    const int N=100011,B=16;
    struct sumireko{int to,ne;}e[N<<1];int he[N],ecnt;
    void addline(int f,int t){e[++ecnt].to=t;e[ecnt].ne=he[f],he[f]=ecnt;}
    int TAT;
    int n,m,sg[N];bool vis[N];
    int rt[N],tcnt;
    int son[N<<6][2],size[N<<6],tag[N<<6];
    void fuckup(int px){size[px]=size[son[px][0]]+size[son[px][1]];}
    void fuckdown(int px,int b)
    {
    	if(!tag[px]) return;
    	if((tag[px]>>b)&1) swap(son[px][0],son[px][1]);
    	tag[son[px][0]]^=tag[px],tag[son[px][1]]^=tag[px],tag[px]=0;
    }
    int merge(int px,int py,int b=B)
    {
    	if(!px||!py) return px|py;if(b==-1) return px;
    	fuckdown(px,b),fuckdown(py,b);
    	son[px][0]=merge(son[px][0],son[py][0],b-1);
    	son[px][1]=merge(son[px][1],son[py][1],b-1);
    	fuckup(px);return px;
    }
    void insert(int &px,int v,int b=B)
    {
    	if(!px) px=++tcnt,size[px]=1;if(b==-1) return;
    	fuckdown(px,b);insert(son[px][(v>>b)&1],v,b-1);
    	fuckup(px);
    }
    int query(int px,int b=B)
    {
    	if(b==-1) return 0;fuckdown(px,b);
    	return size[son[px][0]]<(1<<b)?query(son[px][0],b-1):query(son[px][1],b-1)|(1<<b);
    }
    void dfs(int x,int f=0)
    {
    	vis[x]=1;int tmp=0;
    	for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=f)
    		dfs(t,x),tmp^=sg[t];
    	for(int i=he[x],t=e[i].to;i;i=e[i].ne,t=e[i].to)if(t!=f)
    		tag[rt[t]]^=(tmp^sg[t]),rt[x]=merge(rt[x],rt[t]);
    	insert(rt[x],tmp);sg[x]=query(rt[x]);
    }
    void ESM()
    {
    	read(n,m);for(int i=1,x,y;i<=m;i++) read(x,y),addline(x,y),addline(y,x);
    	int ans=0;for(int i=1;i<=n;i++)if(!vis[i]) dfs(i),ans^=sg[i];
    	puts(ans?"Alice":"Bob");
    }
    void memclr()
    {
    	memset(he+1,0,n*4),ecnt=0;
    	memset(vis+1,0,n);memset(sg+1,0,n*4);
    	memset(son+1,0,tcnt*8),memset(size+1,0,tcnt*4),memset(tag+1,0,tcnt*4);
    	memset(rt+1,0,n*4),tcnt=0;
    }
    int main()
    {
    	read(TAT);while(TAT--) ESM(),memclr();
    	return 0;
    }
    }
    int main(){return RKK::main();}
    
    
  • 相关阅读:
    「总结」容斥。二.反演原理 3.约数容斥
    「总结」容斥。二.反演原理 2.组合容斥
    「总结」容斥。二.反演原理 1.子集容斥
    「总结」容斥。一.容斥原理
    「考试」num (破800纪念)
    「刷题」 网络
    「考试」 Or
    「考试」weight
    「刷题」GERALD07加强版
    「刷题」Triple
  • 原文地址:https://www.cnblogs.com/rikurika/p/13307620.html
Copyright © 2011-2022 走看看