原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html

题解

首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案。

对于一个树就是枚举一下从根出发到哪一个节点为止的路径被删掉了,剩下所有的子树的sg值xor起来,对于每一个路径后的答案取一个 mex 。

我们考虑快速的做这个过程。

直接写个 Trie 再 DSU on tree 就好了,只要支持查询 mex 和整棵 trie 对某一个值 xor 这两种操作就好了。

时间复杂度 $O(n\log ^2n)$ 。

P.S. 可以用线段树合并优化复杂度。

代码

#pragma GCC optimize("Ofast","inline")
#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof (x))
#define For(i,a,b) for (int i=a;i<=b;i++)
#define Fod(i,b,a) for (int i=b;i>=a;i--)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
#define outval(x) printf(#x" = %d\n",x)
#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
#define outtag(x) puts("----------"#x"----------")
#define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
For(_v2,L,R)printf("%d ",a[_v2]);puts("");
using namespace std;
typedef long long LL;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=100005;
namespace Trie{
const int S=N*20*20;
int son[S][2],size[S],c=0;
#define ls son[x][0]
#define rs son[x][1]
void Init(){
while (c)
clr(son[c]),size[c]=0,c--;
}
void Ins(int &x,int d,int v,int tag){
if (!x)
x=++c,size[x]=1;
if (d<0)
return;
Ins(son[x][(v^tag)>>d&1],d-1,v,tag);
size[x]=size[ls]+size[rs];
}
void Get(int x,int d,int v,int tag,vector <int> &vec){
if (!x)
return;
if (d<0)
return vec.pb(v);
Get(son[x][tag>>d&1],d-1,v,tag,vec);
Get(son[x][~tag>>d&1],d-1,v|(1<<d),tag,vec);
}
int Ask(int x,int d,int v,int tag){
if (d<0)
return v;
if (size[son[x][tag>>d&1]]<(1<<d))
return Ask(son[x][tag>>d&1],d-1,v,tag);
else
return Ask(son[x][~tag>>d&1],d-1,v|(1<<d),tag);
}
#undef ls
#undef rs
}
int n,m;
vector <int> e[N];
struct trie{
int rt,tag;
}t[N];
int cnt;
int size[N],son[N],sg[N],id[N];
void dfs(int x,int pre){
size[x]=1,son[x]=0;
for (auto y : e[x])
if (y!=pre){
dfs(y,x);
size[x]+=size[y];
if (!son[x]||size[son[x]]<size[y])
son[x]=y;
}
}
vector <int> gid;
void dfs2(int x,int pre){
sg[x]=0;
int s=0;
for (auto y : e[x])
if (y!=pre){
dfs2(y,x);
s^=sg[y];
}
if (!son[x])
id[x]=++cnt,t[cnt].rt=t[cnt].tag=0;
else
t[id[x]=id[son[x]]].tag^=s^sg[son[x]];
trie &now=t[id[x]];
Trie::Ins(now.rt,17,s,now.tag);
for (auto y : e[x])
if (y!=pre&&y!=son[x]){
gid.clear();
Trie::Get(t[id[y]].rt,17,0,t[id[y]].tag,gid);
for (auto v : gid)
Trie::Ins(now.rt,17,v^(s^sg[y]),now.tag);
}
sg[x]=Trie::Ask(now.rt,17,0,now.tag);
}
void Main(){
n=read(),m=read();
For(i,0,n)
e[i].clear(),size[i]=0;
For(i,1,m){
int x=read(),y=read();
e[x].pb(y),e[y].pb(x);
}
cnt=0;
int ans=0;
Trie::Init();
For(i,1,n)
if (!size[i]){
dfs(i,0);
dfs2(i,0);
ans^=sg[i];
}
puts(ans?"Alice":"Bob");
}
int main(){
int T=read();
while (T--)
Main();
return 0;
}

  

UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie的更多相关文章

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

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

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

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

  3. [UOJ#274][清华集训2016]温暖会指引我们前行

    [UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...

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

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

  5. [BZOJ4730][清华集训2016][UOJ266] Alice和Bob又在玩游戏

    题意:俩智障又在玩游戏.规则如下: 给定n个点,m条无向边(m<=n-1),保证无环,对于每一个联通块,编号最小的为它们的根(也就是形成了一片这样的森林),每次可以选择一个点,将其本身与其祖先全 ...

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

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

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

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

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

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

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

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

随机推荐

  1. 2018-2019 20165232 Exp5 MSF基础应用

    2018-2019 20165232 Exp5 MSF基础应用 一.原理与实践说明 1.实践内容 本实践目标是掌握metasploit的基本应用方式,重点常用的三种攻击方式的思路.具体需要完成: 一个 ...

  2. Redis 使用介绍-Linux-Bash

    1.进入Bash redis-cli 2.查看所有的key keys * 1.Key-Value 1.1.查看key-value值 1.2.修改key值 2.List 1> string lis ...

  3. Asp.Net Core 新篇章

    一. 二. 三. 系列章节 第一节:.Net Core环境的安装和常用指令 第X节:XXXXXXXXXXXXXXXXXXXXXXXXXXXX 第X节:XXXXXXXXXXXXXXXXXXXXXXXXX ...

  4. 《Java》第八周学习总结

    第八周学习内容:课本第15章节的内容泛型与集合框架  主要内容有 -泛型-链表-堆栈-散列映射-树集-树映射 重点和难点-重点:泛型和集合的使用码云:https://gitee.com/ShengHu ...

  5. 一个Ajax读数据并使用IScroll显示辅助类

    花了2天时间对iscroll进行了一些封装,方便进行ajax读取数据和显示 1.IScroll直接使用的话还是挺麻烦的,特别是牵涉到分页加载动态加载数据时,以下是核心实现代码. 2.Loading提示 ...

  6. PMP知识点(三)——挣值计算汇总表

    在新标签页打开. 附参考图 资料地址:http://pan.baidu.com/s/1bMNroq

  7. mint-ui Picker设置指定初始值

    最近做的项目公司需求是信息输入页设置地址跳转下一页后,再返回信息输入页查看信息时,地址要默认显示前面选择的地址,以此记录下,需要小伙伴可以看看 data{return{}}中设置   :slots 在 ...

  8. Python爬虫案例-获取最新的中国行政区域划分

    源网页:中国统计局标准 http://www.stats.gov.cn/tjsj/tjbz/tjyqhdmhcxhfdm/2016/ 打开网页后可以分析出行政区域划分共分为5层 根据传入参数,生成网页 ...

  9. Java 多线程 - 锁优化

    http://www.cnblogs.com/pureEve/p/6421273.html https://www.cnblogs.com/mingyao123/p/7424911.html

  10. #20175204 张湲祯 2018-2019-2《Java程序设计》第六周学习总结

    20175204 张湲祯 2018-2019-2<Java程序设计>第六周学习总结 教材学习内容总结 -第七章内部类与异常类要点: 一.内部类: Java支持在一个类中定义另一个类,这样的 ...