题意:俩智障又在玩游戏。规则如下:

给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全部删除,不能操作者输。判断先手胜负。

题解:比较神的一道题。

我们现在要解决的问题是怎么求解一棵子树的SG值,首先把根删掉的情况考虑,这很好办,直接把子树的sg异或起来就好,关键是如果删除点在子树里怎么办。

这里用到了一个巧妙的东西,trie。怎么会用这个呢?因为删除子树里的节点就相当于是子树里这种对应的情况再异或上外边子树的sg。但是我们不可能用一般的方法来存一棵子树里所有的sg。这个时候trie应运而生。我们处理子树之后,把它合并上来,就能得到当前节点的所有拓展局面的sg了。这里注意,合并子树前要先在子树上打一个tag(因为它是要异或上外面所有子树sg的)。

算法很清晰了,dfs下去,合并上来。这里的trie还要打tag。所有细节就这么多。

 #include<bits/stdc++.h>
using namespace std;
#define LL long long
#define N 100005 inline LL read(){
LL x=,f=; char a=getchar();
while(a<'' || a>'') {if(a=='-') f=-; a=getchar();}
while(a>='' && a<='') x=x*+a-'',a=getchar();
return x*f;
} int n,m,T,bin[],head[N],cnt,id,tag[N*],rt[N],ls[N*],rs[N*],sg[N],sz[N*];
bool vis[N]; struct edges{
int to,next;
}e[*N]; inline void insert(){
int u=read(),v=read();
e[++cnt]=(edges){v,head[u]};head[u]=cnt;
e[++cnt]=(edges){u,head[v]};head[v]=cnt;
} inline void init(){
bin[]=; for(int i=;i<=;i++) bin[i]=bin[i-]<<;
} inline void pushdown(int k,int level){
if(!tag[k]) return;
if(bin[level-]&tag[k]) swap(ls[k],rs[k]);
tag[ls[k]]^=tag[k]; tag[rs[k]]^=tag[k];
tag[k]=;
} inline void reset(){
for(int i=;i<=n;i++) head[i]=sg[i]=rt[i]=,vis[i]=;
for(int i=;i<=id;i++) tag[i]=ls[i]=rs[i]=sz[i]=;
cnt=; id=;
} void ins(int& k,int x,int level){ // 0 is on the left
k=++id; sz[k]=;
if(!level) return;
if(x&bin[level-]) ins(rs[k],x,level-);
else ins(ls[k],x,level-);
} int merge(int x,int y,int level){
if(!x || !y) return x|y;
pushdown(x,level); pushdown(y,level);
ls[x]=merge(ls[x],ls[y],level-); rs[x]=merge(rs[x],rs[y],level-);
sz[x]=sz[ls[x]]+sz[rs[x]]+(level?:);
return x;
} void dfs(int x,int fa){
vis[x]=; int t=;
for(int i=head[x];i;i=e[i].next){
if(fa==e[i].to) continue;
dfs(e[i].to,x); t^=sg[e[i].to];
}
ins(rt[x],t,);
for(int i=head[x];i;i=e[i].next){
if(fa==e[i].to) continue;
tag[rt[e[i].to]]^=t^sg[e[i].to];
rt[x]=merge(rt[x],rt[e[i].to],);
}
for(int now=rt[x],i=;i;i--){ // i is the i th digit int binary system
pushdown(now,i);
if(sz[ls[now]]<bin[i-]) now=ls[now];
else sg[x]|=bin[i-],now=rs[now];
}
} inline void solve(){
n=read(); m=read(); int ans=;
for(int i=;i<=m;i++) insert();
for(int i=;i<=n;i++) if(!vis[i]) dfs(i,),ans^=sg[i];
puts(ans?"Alice":"Bob");
} int main(){
init(); T=read();
while(T--){
solve();
reset();
}
return ;
}

[BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏的更多相关文章

  1. UOJ #266 【清华集训2016】 Alice和Bob又在玩游戏

    题目链接:Alice和Bob又在玩游戏 这道题就是一个很显然的公平游戏. 首先\(O(n^2)\)的算法非常好写.暴力枚举每个后继计算\(mex\)即可.注意计算后继的时候可以直接从父亲转移过来,没必 ...

  2. UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...

  3. uoj#266. 【清华集训2016】Alice和Bob又在玩游戏(博弈论)

    传送门 完了我连sg函数是个啥都快忘了 设\(sg[u]\)为以\(u\)为根节点的子树的\(sg\)函数值,\(rem[u]\)表示\(u\)到根节点的路径删掉之后剩下的游戏的异或值 根节点\(u\ ...

  4. 【清华集训2016】Alice和Bob又在玩游戏

    不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达 ...

  5. UOJ 266 - 【清华集训2016】Alice和Bob又在玩游戏(SG 定理+01-trie)

    题面传送门 神仙题. 首先注意到此题的游戏是一个 ICG,故考虑使用 SG 定理解决这个题,显然我们只需对每个连通块计算一遍其 SG 值异或起来检验是否非零即可.注意到我们每删除一个点到根节点的路径后 ...

  6. [UOJ266]Alice和Bob又在玩游戏

    [UOJ266]Alice和Bob又在玩游戏 Tags:题解 作业部落 评论地址 TAG:博弈 题意 不同于树的删边游戏,删掉一个点删去的是到根的路径 题解 这题只和计算\(SG\)有关,博弈的有关内 ...

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

    uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数) uoj 题解时间 考虑如何求出每棵树(子树)的 $ SG $ . 众所周知一个状态的 $ SG $ 是其后继的 $ mex $ ...

  8. bzoj4730: Alice和Bob又在玩游戏

    Description Alice和Bob在玩游戏.有n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最 小的点.Alice和Bob轮流操作,每回合 ...

  9. 【bzoj4730】 Alice和Bob又在玩游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=4730 (题目链接) 题意 给出一个森林,两个人轮流操作,每次把一个节点以及它的祖先全部抹去,无节点可 ...

随机推荐

  1. 信息属性列表关键字 info.plist

    本文转载至  http://blog.csdn.net/zaitianaoxiang/article/details/6650491 本附录说明了那些可以在束和包的属性列表文件中定义的关键字. 束关键 ...

  2. openssl 升级 操作 -1

    好多公司都会用绿盟扫描系统漏洞,里边就会涉及到ssl 漏洞,原因是openssl 版本低导致,会让你升级到指定版本.下面就介绍一下openssl 版本升级的操作方案. 一. 查看系统版本 [root@ ...

  3. 【BZOJ2648】SJY摆棋子 KDtree

    [BZOJ2648]SJY摆棋子 Description 这天,SJY显得无聊.在家自己玩.在一个棋盘上,有N个黑色棋子.他每次要么放到棋盘上一个黑色棋子,要么放上一个白色棋子,如果是白色棋子,他会找 ...

  4. 转 谈谈JS里的{ }大括号和[ ]中括号的用法,理解后就可以看懂JSON结构了。

    一.{ } 大括号,表示定义一个对象,大部分情况下要有成对的属性和值,或是函数. 如:var LangShen = {"Name":"Langshen",&qu ...

  5. 对django模型中的objects的理解

    object是模型属性,用于模型对象和数据库交互. object=Manager()是管理器类型的对象,是model和数据库进行查询的接口 可以自定义管理对象 books=models.Manager ...

  6. 前端基础 & 初识CSS

    CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义如何显示HTML元素.l 当浏览器读到一个样式表,它就会按照这个样式表来对文档进行格式化(渲染). CSS语法 每个CS ...

  7. Python3.6全栈开发实例[020]

    20.判断一个数是否是水仙花数, 水仙花数是一个三位数, 三位数的每一位的三次方的和还等于这个数. 那这个数就是一个水仙花数, 例如: 153 = 1**3 + 5**3 + 3**3 num = i ...

  8. PAT 1069. 微博转发抽奖(20)

    小明PAT考了满分,高兴之余决定发起微博转发抽奖活动,从转发的网友中按顺序每隔N个人就发出一个红包.请你编写程序帮助他确定中奖名单. 输入格式: 输入第一行给出三个正整数M(<= 1000).N ...

  9. VM和Windows Ping不通

    连接模式:桥接 Linux上1.修改 /etc/sysconfig/network-scripts/ifcfg-enp0s3 文件 ONBOOT=yes2.service network restar ...

  10. Java基础—访问权限控制

    Java中访问权限控制的作用: 为了使用户不要触碰那些他们不该触碰的部分,这些部分对于类内部的操作时必要的,但是它并不属于客户端程序员所需接口的一部分. 为了让类库设计者可用更改类的内部工作方式,而不 ...