【清华集训2016】Alice和Bob又在玩游戏
不难的题目。因为SG性质,所以只需要对一棵树求出。
然后如果发现从上往下DP不太行,所以从下往上DP。
考虑一个点对子树的合并,考虑下一个删的点在哪一个子树,那么剩下的状态实际上就是把一个子树所有能达到的状态异或上一个数。
此时还有不到子树的状态,直接插入子树SG异或值。
所以显然,就是维护一个支持全部异或,以及状态合并,查询mex的数据结构,直接trie合并带tag就好了。
时空复杂度 \(O(n \log n)\)
#include <bits/stdc++.h>
const int MAXN = 100010;
const int UP = 21;
const int MN = MAXN * (UP + 1);
int son[MN][2], val[MN], tag[MN], txt;
void mktag(int u, int v) { tag[u] ^= v; }
void pushdown(int u, int dig) {
if (tag[u]) {
if (son[u][0]) mktag(son[u][0], tag[u]);
if (son[u][1]) mktag(son[u][1], tag[u]);
if (tag[u] >> dig & 1)
std::swap(son[u][0], son[u][1]);
tag[u] = 0;
}
}
void update(int u) { val[u] = val[son[u][0]] + val[son[u][1]]; }
void insert(int & x, int v, int dig = UP) {
if (!x) x = ++txt, son[x][0] = son[x][1] = val[x] = tag[x] = 0;
if (dig == -1) return (void) (val[x] = 1);
pushdown(x, dig);
insert(son[x][v >> dig & 1], v, dig - 1);
update(x);
}
int merge(int x, int y, int dig = UP) {
if (!x || !y) return x | y;
pushdown(x, dig), pushdown(y, dig);
son[x][0] = merge(son[x][0], son[y][0], dig - 1);
son[x][1] = merge(son[x][1], son[y][1], dig - 1);
if (dig != -1) update(x);
return x;
}
int query(int u, int dig = UP) {
if (!u) return 0;
if (val[son[u][0]] < (1 << dig)) return query(son[u][0], dig - 1);
return query(son[u][1], dig - 1) | 1 << dig;
}
int head[MAXN], nxt[MAXN << 1], to[MAXN << 1], tot;
void addedge(int b, int e) {
nxt[++tot] = head[b]; to[head[b] = tot] = e;
nxt[++tot] = head[e]; to[head[e] = tot] = b;
}
int sg[MAXN], rts[MAXN];
bool vis[MAXN];
int solve(int u, int fa = 0) {
vis[u] = true;
int pre = 0, & rt = rts[u];
for (int i = head[u]; i; i = nxt[i]) if (to[i] != fa)
solve(to[i], u), pre ^= sg[to[i]];
for (int i = head[u]; i; i = nxt[i])
if (to[i] != fa) {
mktag(rts[to[i]], pre ^ sg[to[i]]);
rt = merge(rt, rts[to[i]]);
}
insert(rt, pre);
sg[u] = query(rt);
return rt;
}
int n, m;
int main() {
std::ios_base::sync_with_stdio(false), std::cin.tie(0);
int T; std::cin >> T;
while (T --> 0) {
std::cin >> n >> m;
for (int i = 1; i <= m; ++i) {
int t1, t2; std::cin >> t1 >> t2;
addedge(t1, t2);
}
int ans = 0;
for (int i = 1; i <= n; ++i) if (!vis[i])
solve(i), ans ^= sg[i];
std::cout << (ans ? "Alice" : "Bob") << '\n';
tot = 0; memset(head, 0, n + 1 << 2);
memset(vis, 0, n + 1); txt = 0;
memset(rts, 0, n + 1 << 2);
}
return 0;
}
【清华集训2016】Alice和Bob又在玩游戏的更多相关文章
- 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\)即可.注意计算后继的时候可以直接从父亲转移过来,没必 ...
- [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又在玩游戏 博弈,DSU on Tree,Trie
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ266.html 题解 首先我们可以直接暴力 $O(n^2)$ 用 sg 函数来算答案. 对于一个树就是枚举 ...
- 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 值异或起来检验是否非零即可.注意到我们每删除一个点到根节点的路径后 ...
- 【bzoj4730】 Alice和Bob又在玩游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=4730 (题目链接) 题意 给出一个森林,两个人轮流操作,每次把一个节点以及它的祖先全部抹去,无节点可 ...
随机推荐
- ubuntu18.04 开机自动启动脚本的坑
哇 这个真的难受 找了半天的方案不能用 自暴自弃用的图形界面设置
- C++笔记(3)——string.h相关的一些小知识
strlen() 用于得到字符数组中第一个\0前的字符的个数,格式如下: strlen(数组); 例子: #include <stdio.h> #include <string.h& ...
- 检测Python程序本身是否已经在运行
为runner.py实现一个函数,检测是否有其他的runner.py进程在正在执行? 除主要用到os模块,还用到了第三方模块psutil
- myBatis+Spring+SpringMVC框架面试题整理
myBatis+Spring+SpringMVC框架面试题整理(一) 2018年09月06日 13:36:01 新新许愿树 阅读数 14034更多 分类专栏: SSM 版权声明:本文为博主原创文章 ...
- springboot2整合zookeeper集成curator
步骤: 1- pom.xml <dependency> <groupId>org.apache.curator</groupId> <artifactId&g ...
- 图片哈希概论及python中如何实现对比两张相似的图片
Google 以图搜图的原理,其中的获取图片 hash 值的方法就是 AHash. 每张图片都可以通过某种算法得到一个 hash 值,称为图片指纹,两张指纹相近的图片可以认为是相似图片. 以图搜图的原 ...
- JavaScript快速排序法实现数组排序
大致分三步: 1.找基准(一般是以中间项为基准) 2.遍历数组,小于基准的放在left,大于基准的放在right 3.递归 var arr = [10,8,6,9,1,7,1,13,5,1,9]; / ...
- vue-router实现原理
vue-router实现原理 近期面试,遇到关于vue-router实现原理的问题,在查阅了相关资料后,根据自己理解,来记录下.我们知道vue-router是vue的核心插件,而当前vue项目一般都是 ...
- Java中的字符串常量池,栈和堆的概念
问题:String str = new String(“abc”),“abc”在内存中是怎么分配的? 答案是:堆内存.(Tips:jdk1.8 已经将字符串常量池放在堆内存区) 题目考查的为Ja ...
- 动画学习之WIFI图形绘制
Android原生动画概述: 对于APP开发中涉及到的一些动画基本上都可以用Android提供的各种原生动画类来实现,所以在学习自定义动画之前首先来对原生动画进行一个基本的了解,这里不详细对每一个原生 ...