UOJ#266. 【清华集训2016】Alice和Bob又在玩游戏 博弈,DSU on Tree,Trie
原文链接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的更多相关文章
- 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\)有关,博弈的有关内 ...
- [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\ ...
- UOJ 266 - 【清华集训2016】Alice和Bob又在玩游戏(SG 定理+01-trie)
题面传送门 神仙题. 首先注意到此题的游戏是一个 ICG,故考虑使用 SG 定理解决这个题,显然我们只需对每个连通块计算一遍其 SG 值异或起来检验是否非零即可.注意到我们每删除一个点到根节点的路径后 ...
- 【清华集训2016】Alice和Bob又在玩游戏
不难的题目.因为SG性质,所以只需要对一棵树求出. 然后如果发现从上往下DP不太行,所以从下往上DP. 考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达 ...
随机推荐
- (N叉树 递归) leetcode 590. N-ary Tree Postorder Traversal
Given an n-ary tree, return the postorder traversal of its nodes' values. For example, given a 3-ary ...
- 第二周博客作业<西北师范大学|李晓婷>
1.助教博客链接:https://home.cnblogs.com/u/lxt-/ 2.点评作业内容: https://www.cnblogs.com/dxd123/p/10494907.html#4 ...
- 安装redis服务
wget http://download.redis.io/releases/redis-3.2.6.tar.gz tar -zxvf redis-3.2.6.tar.gzcd redis-3.2.6 ...
- vue-输入框change事件并获取值
1.html <input type="text" @change="specifiName($event)" /> 2.js var vm = n ...
- jmeter 多个sql写在一个jdbc请求中注意事项
在url里面加上?allowMultiQueries=true 类型选callableStatement
- (七) UVC框架分析
title: UVC框架分析 date: 2019/4/23 19:50:00 toc: true --- UVC框架分析 源码的位置在drivers\media\video\uvc,查看下Makef ...
- python 基础部分重点复习整理2
把这里的题目争取刷一遍 博客记录 python的ORM框架peewee SQLAlchemy psycopg2 Django 在1 的基础上,重点突出自己以前没注意的,做到精而不杂!!! Python ...
- C++预编译头文件 – stdafx.h
预编译头文件的由来 也许请教了别的高手之后,他们会告诉你,这是预编译头,必须包含.可是,这到底是为什么呢?预编译头有什么用呢? 咱们从头文件的编译原理讲起.其实头文件并不神秘,其在编译时的作用,就是把 ...
- H5_0006:JS判断PC,平板,手机平台的方法
<script type="text/javascript"> //平台.设备和操作系统var system = { win: false, mac: false, x ...
- 2018-2019-2 《网络对抗技术》Exp0 Kali安装 Week1 20165237
2018-2019-2 <网络对抗技术>Exp0 Kali安装 Week1 20165237 安装虚拟机 首先创建虚拟机 创建好虚拟机后,打开虚拟机进行安装.第一步选择Graphcal i ...