不难的题目。因为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又在玩游戏的更多相关文章

  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. [UOJ266]Alice和Bob又在玩游戏

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

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

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

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

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

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

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

  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. 【bzoj4730】 Alice和Bob又在玩游戏

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

随机推荐

  1. Git和Github的使用

    Git和Github的基本操作 一.了解Git和Github 1.什么是GIT? Git是一个免费.开源的版本控制软件 2.什么是版本控制系统? 版本控制是一种记录一个或若干个文件内容变化,以便将来查 ...

  2. 云数据库 Redis 版

    首先观看视频简介 云数据库 Redis 版是一项易于部署和管理的按需数据库服务,与 Redis 协议兼容.云数据库 Redis 版通过从内存缓存中检索数据而提供高速数据读写功能,并通过同时使用内存和硬 ...

  3. C++练习 | 类的继承与派生练习(1)

    #include <iostream> #include <cmath> #include <cstring> #include <string> #i ...

  4. redis 学习(6)-- 集合类型

    redis 学习(6)-- 集合类型 set 结构 无序 无重复 集合间操作 set 集合内操作 命令 含义 sadd key memebr1 [member2...] 向集合中添加一个或多个成员 s ...

  5. postgres 常规操作杂记

    分布式:1.扩容不方便(数据重分布)2.分布键变更很麻烦3.分布键选择(架构设计)谨慎4.跨库join性能差5.分布式事务性能差6.sql限制多,功能确实多7.应用改造成本巨大8.全局一致性时间点恢复 ...

  6. MySQL数据库基础-JAVA

    数据库 MySQL初步 MySQL基础认知 (Oracle真的是走哪祸害到哪23333) Java多用MySQL和Oracle SQLServer也收费,但是还行,比Oracle便宜,一个差不多3w多 ...

  7. JDBC2

    1.JDBC连接池 public class JdbcTemplateDemo2 { //Junit单元测试,可以让方法独立执行 //1. 获取JDBCTemplate对象 private JdbcT ...

  8. 在java中使用solr7.2.0 新旧版本创建SolrClient对比

    在Java中使用solr 版本7.2.0 solrj已经更新到了7.2.0,新版本solr获取SolrClient的方式也和之前旧版本有所不同 solr6.5开始不推荐直接使用HttpSolrClie ...

  9. PowerDesigner连接 MySQL 生成 ER图

    powerdesigner 16.5 http://www.pcsoft.com.cn/soft/27495.html jdk 1.8 32位 https://mirrors.huaweicloud. ...

  10. 利用nethogs查看哪些进程占用网络带宽

    一.安装nethogs centos6版本安装: 1.安装依赖包 [root@hlsms-fensheng- ~]# yum install ncurses* 已加载插件:fastestmirror, ...