[UOJ266]Alice和Bob又在玩游戏

[UOJ266]Alice和Bob又在玩游戏

Tags:题解

作业部落

评论地址


TAG:博弈

题意

不同于树的删边游戏,删掉一个点删去的是到根的路径

题解

这题只和计算\(SG\)有关,博弈的有关内容可以移步这篇博客
这和翻棋子游戏不同!每个点不能单独考虑
考虑计算一个游戏(子树\(x\))的\(SG\):对其后继状态取\(mex\)
这里的后继状态是指去掉子树\(x\)内任意一个点所得的若干子游戏的异或和(联通块)

\(SG[x]\)维护子树\(x\)游戏的\(SG\)值,考虑转移给父亲\(y\)
游戏\(y\)可以删去\(y\)结点,后继状态便是\(y\)各儿子的\(SG\)的异或和
游戏\(y\)可以删去任意\(x\)子树内的点,这时\(x\)子树内删去任意结点的后继状态会多出\(x\)的兄弟
\(SG[x]=mex\{S\}\),这时我们要求一个数据结构能将\(S\)中每个元素异或上一个数再合并给\(y\)\(S_y\)
带懒标记的\(Trie\)就好了

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define lc ch[x][0]
#define rc ch[x][1]
using namespace std;
int read()
{
	char ch=getchar();int h=0,t=1;
	while((ch>'9'||ch<'0')&&ch!='-') ch=getchar();
	if(ch=='-') t=-1,ch=getchar();
	while(ch>='0'&&ch<='9') h=h*10+ch-'0',ch=getchar();
	return h*t;
}
const int N=4000100;
int n,m,T,ans,cnt,head[N],ch[N][2],node,siz[N];
int vis[N],SG[N],rt[N],tag[N];
struct edge{int next,to;}a[N<<1];
void link(int x,int y) {a[++cnt]=(edge){head[x],y};head[x]=cnt;}
void pushdown(int x,int d)
{
	int &s=tag[x]; if(!s) return;
	if(s&(1<<d)) swap(lc,rc);
	tag[lc]^=s;tag[rc]^=s;s=0;
}
int Merge(int x,int y,int d)
{
	if(!x||!y) return x+y;
	pushdown(x,d);pushdown(y,d);
	lc=Merge(lc,ch[y][0],d-1);
	rc=Merge(rc,ch[y][1],d-1);
	if(lc||rc) siz[x]=siz[lc]+siz[rc];
	return x;
}
void Newnode(int &x) {x=++node;lc=rc=tag[x]=0;siz[x]=1;}
void Insert(int &x,int k,int d)
{
	if(!x) Newnode(x); if(d==-1) return;
	pushdown(x,d);
	Insert(ch[x][k&(1<<d)?1:0],k,d-1);
	siz[x]=siz[lc]+siz[rc];
}
int Query(int x,int d)
{
	if(d==-1) return 0; pushdown(x,d);
	if(siz[lc]<(1<<d)) return Query(lc,d-1);
	else return Query(rc,d-1)|(1<<d);
}
void DFS(int x,int fa)
{
	vis[x]=1;int res=0;
	for(int i=head[x],R=a[i].to;i;i=a[i].next,R=a[i].to)
		if(R!=fa) DFS(R,x),res^=SG[R];
	for(int i=head[x],R=a[i].to;i;i=a[i].next,R=a[i].to)
		if(R!=fa) tag[rt[R]]^=res^SG[R],rt[x]=Merge(rt[x],rt[R],16);
	Insert(rt[x],res,16);
	SG[x]=Query(rt[x],16);
}
void work()
{
	ans=cnt=0;
	for(int i=1;i<=n;i++)
		rt[i]=vis[i]=head[i]=SG[i]=0;
	n=read();m=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();
		link(x,y);link(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!vis[i]) node=0,DFS(i,0),ans^=SG[i];
	ans?puts("Alice"):puts("Bob");
}
int main()
{
	T=read();while(T--) work();
}

posted @ 2018-08-05 21:57  饕餮传奇  阅读(963)  评论(0编辑  收藏  举报