UOJ 266 - 【清华集训2016】Alice和Bob又在玩游戏(SG 定理+01-trie)
神仙题。
首先注意到此题的游戏是一个 ICG,故考虑使用 SG 定理解决这个题,显然我们只需对每个连通块计算一遍其 SG 值异或起来检验是否非零即可。注意到我们每删除一个点到根节点的路径后留下的是一些互不影响的子树,并且剩余部分的 SG 值就是剩余子树的 SG 值异或起来,因此我们考虑设 \(sg_u\) 表示 \(u\) 子树部分的 SG 值,我们再实时维护一个 \(t_v\) 表示删除 \(v\) 到当前计算的节点(譬如我们计算 \(sg_u\) 的时候当前计算的节点就是 \(u\))之后,剩余部分的 SG 值的异或和。那么显然 \(sg_u\) 就等于所有 \(u\) 子树内的点 \(v\) 的 \(t_v\) 的 MEX。
因此我们有了 \(n^2\) 的解法,直接暴力枚举 \(u\) 子树内所有点并计算其 MEX。
考虑优化这个过程,当我们计算 \(u\) 子树的 SG 时,我们首先 DFS 一遍 \(u\) 的所有儿子 \(v\) 并计算 \(v\) 子树内所有点的 \(sg_v\) 及 \(t_v\),记 \(S=\operatorname{xor}\limits_{v\in son_u}sg_v\),那么必然有 \(t_u=S\)。而显然对于 \(u\) 的一个儿子 \(v\) 而言,我们在 DFS \(v\) 的时候,所有 \(v\) 子树中的点 \(w\) 本来的 \(t_w\) 肯定是删除 \(w\) 到 \(v\) 路径上的点后,剩余部分 SG 值的异或和,现在根节点由 \(v\) 变成了 \(u\),删除 \(w\) 到 \(u\) 之后的剩余部分与删除 \(w\) 到 \(v\) 之后的剩余部分相比,肯定会多出一部分出来,而这多出的部分又显然是 \(u\) 的所有儿子扣掉 \(v\),它们的 SG 值的异或和即为 \(S\oplus sg_v\),故我们需要将所有 \(v\) 子树中的 \(w\) 的 \(t_w\) 都异或上 \(S\oplus sg_v\)。
可是这样还是没法从本质上优化之前 \(n^2\) 的暴力解法。注意到此题设计异或运算,因此考虑 01-trie,我们对于每个点 \(u\) 维护一个 01-trie,里面存了 \(u\) 子树中所有点的 \(t\) 值,注意到”将 \(v\) 子树中所有点的 \(t\) 值都异或上某个值“这个操作相当于对整棵 trie 打一个 tag,这个显然是可以在常数时间内完成的,而当我们计算 \(sg_u\) 时合并子树信息时,可以像去年省选 D2T2 一样通过类似于线段树合并/堆合并的方式,将所有儿子节点的 01-trie 合并,求一个集合的 MEX 时就在 01-trie 上二分即可。简单来说就是要实现一下四个操作:
- 对每个儿子节点的 01-trie 整体打一个异或的标记
- 将儿子节点的 01-trie 合并起来
- 在当前节点的 01-trie 中插入 \(t_u=\operatorname{xor}\limits_{v\in son_u}sg_v\)
- 在 01-trie 上二分找到第一个未出现的位置
这样即可将时间复杂度优化到 \(n\log n\)。
const int MAXN=1e5;
const int MAXB=18;
const int MAXP=MAXN*40;
int n,m,hd[MAXN+5],to[MAXN*2+10],nxt[MAXN*2+10],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
struct node{int ch[2],lz,siz;} s[MAXP+5];
int rt[MAXN+5],ncnt=0,sg[MAXN+5],vis[MAXN+5];
void clear(){
memset(hd,0,sizeof(hd));ec=0;
memset(sg,0,sizeof(sg));memset(vis,0,sizeof(vis));
for(int i=1;i<=ncnt;i++) s[i].ch[0]=s[i].ch[1]=s[i].lz=s[i].siz=0;
memset(rt,0,sizeof(rt));ncnt=0;
}
void pushup(int k){s[k].siz=s[s[k].ch[0]].siz+s[s[k].ch[1]].siz;}
void pushdown(int k,int d){
if(s[k].lz){
if(s[k].lz>>d&1) swap(s[k].ch[0],s[k].ch[1]);
s[s[k].ch[0]].lz^=s[k].lz;s[s[k].ch[1]].lz^=s[k].lz;
s[k].lz=0;
}
}
void insert(int &k,int x,int d){
if(!k) k=++ncnt;if(!~d) return s[k].siz=1,void();
pushdown(k,d);insert(s[k].ch[x>>d&1],x,d-1);pushup(k);
}
int query(int k,int d){
if(!~d) return 0;pushdown(k,d);//printf("%d %d %d\n",k,d,s[k].siz);
if(s[s[k].ch[0]].siz>=(1<<d)) return query(s[k].ch[1],d-1)|(1<<d);
else return query(s[k].ch[0],d-1);
}
int merge(int x,int y,int d){
if(!x||!y) return x+y;int z=++ncnt;
if(!~d) return s[z].siz=1,z;
pushdown(x,d);pushdown(y,d);
s[z].ch[0]=merge(s[x].ch[0],s[y].ch[0],d-1);
s[z].ch[1]=merge(s[x].ch[1],s[y].ch[1],d-1);
return pushup(z),z;
}
void dfs(int x,int f){
int sum=0;vis[x]=1;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;
dfs(y,x);sum^=sg[y];
}
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f) continue;
s[rt[y]].lz^=sg[y]^sum;rt[x]=merge(rt[x],rt[y],MAXB);
} insert(rt[x],sum,MAXB);sg[x]=query(rt[x],MAXB);
// printf("%d %d\n",x,sg[x]);
}
void solve(){
scanf("%d%d",&n,&m);clear();int sum=0;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
for(int i=1;i<=n;i++) if(!vis[i]) dfs(i,0),sum^=sg[i];
printf("%s\n",(sum==0)?"Bob":"Alice");
}
int main(){int qu;scanf("%d",&qu);while(qu--) solve();return 0;}
UOJ 266 - 【清华集训2016】Alice和Bob又在玩游戏(SG 定理+01-trie)的更多相关文章
- uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数)
uoj266[清华集训2016]Alice和Bob又在玩游戏(SG函数) uoj 题解时间 考虑如何求出每棵树(子树)的 $ SG $ . 众所周知一个状态的 $ SG $ 是其后继的 $ mex $ ...
- UOJ #266 【清华集训2016】 Alice和Bob又在玩游戏
题目链接:Alice和Bob又在玩游戏 这道题就是一个很显然的公平游戏. 首先\(O(n^2)\)的算法非常好写.暴力枚举每个后继计算\(mex\)即可.注意计算后继的时候可以直接从父亲转移过来,没必 ...
- [UOJ#274][清华集训2016]温暖会指引我们前行
[UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...
- [UOJ266]Alice和Bob又在玩游戏
[UOJ266]Alice和Bob又在玩游戏 Tags:题解 作业部落 评论地址 TAG:博弈 题意 不同于树的删边游戏,删掉一个点删去的是到根的路径 题解 这题只和计算\(SG\)有关,博弈的有关内 ...
- UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...
- [BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏
题意:俩智障又在玩游戏.规则如下: 给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全 ...
- bzoj4730: Alice和Bob又在玩游戏
Description Alice和Bob在玩游戏.有n个节点,m条边(0<=m<=n-1),构成若干棵有根树,每棵树的根节点是该连通块内编号最 小的点.Alice和Bob轮流操作,每回合 ...
- uoj#266. 【清华集训2016】Alice和Bob又在玩游戏(博弈论)
传送门 完了我连sg函数是个啥都快忘了 设\(sg[u]\)为以\(u\)为根节点的子树的\(sg\)函数值,\(rem[u]\)表示\(u\)到根节点的路径删掉之后剩下的游戏的异或值 根节点\(u\ ...
- 【清华集训2016】Alice和Bob又在玩游戏
不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达 ...
随机推荐
- 【二食堂】Alpha - Scrum Meeting 3
Scrum Meeting 3 例会时间:4.13 12:00 - 12:30 进度情况 组员 昨日进度 今日任务 李健 1. 继续学习前端知识,寻找一些可用的框架.issue 1. 搭建主页html ...
- OO_JAVA_JML系列作业_单元总结
OO_JAVA_JML系列作业_单元总结 (1)梳理JML语言的理论基础.应用工具链情况 简单梳理 以下三者是jml规格里的核心,对一个方法功能和属性的限制: requires子句:规定方法的前置条件 ...
- 使用vsftpd 搭建ftp服务
ftp 基础服务器基础知识 ftp有三种登录方式.匿名登录(所有用户).本地用户.虚拟用户(guest). FTP工作模式 主动模式:服务端从20端口主动向客户端发起链接. 控制端口21:数据传输端口 ...
- Linux初学者:从不同角度理解Linux系统
在我初学Linux系统时,虽然已经掌握了一些命令,但总觉得还是很混乱.大家新买的笔记本如果是Windows系统,那么第一件事往往就是分区,目的就是将系统和软件分开.然而Linux却没有类似于Windo ...
- [转]技术往事:改变世界的TCP/IP协议
原文链接 : http://www.52im.net/thread-520-1-1.html 1.前言 作为应用层开发人员,接触最多的网络协议通常都是传输层的TCP(与之同处一层的另一个重要协议是UD ...
- 攻防世界 Misc 新手练习区 如来十三掌 Writeup
攻防世界 Misc 新手练习区 如来十三掌 Writeup 题目介绍 题目考点 佛曰加密.base64.Rot13等加密方法的了解 Writeup 下载并打开附件 联想到佛曰加密,复制内容到 佛曰加密 ...
- C++中简单使用HP-Socket
目录 简介 使用方式 实现简单线程池 实现TCP客户端 实现TCP服务端 实现Http客户端 附件 简介 HP-Socket 是一套通用的高性能 TCP/UDP /HTTP 通信 框架 ,包含服务端组 ...
- 计算机网络-3-5-以太网MAC层及交换机
MAC层的硬件地址 在局域网中,硬件地址又称为物理地址或者MAC地址(因为这种地址用在MAC帧中) IEEE 802标准为局域网规定了一种48位(6字节)的全球地址,固化在适配器的ROM中. 如果计算 ...
- asp.net中HttpCookie操作cookie的方法
微软对HttpCookie的定义为"提供创建和操作各 HTTP Cookie 的类型安全方法." HttpCookie的构造函数一共有两个 1.HttpCookie(String) ...
- CodeGuide 300+文档、100+代码库,一个指导程序员写代码的,Github 仓库开源啦!
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.路怎样走,让你们自己挑 B站 视频:https://www.bilibili.com/vi ...