[平等博弈][SG函数][字典树合并] BZOJ 4730: Alice和Bob又在玩游戏
2018-02-24 19:23
357 查看
SolutionSolution
记SuSu为uu到根的链的子树的SG函数值的集合。考虑从子树转移到根。
一种是去掉根,就是把所有子树异或起来。
一种操作在子树内,相当于把子树的SS异或上子树的SG异或和。
集合异或上一个数可以打标记。
集合的合并可以用字典树合并。
求mexmex可以二分。
#include <bits/stdc++.h> #define show(x) cerr << #x << " = " << x << endl using namespace std; typedef long long ll; typedef pair<int, int> Pairs; const int N = 202020; const int M = 4040404; const int K = 18; inline char get(void) { static char buf[100000], *S = buf, *T = buf; if (S == T) { T = (S = buf) + fread(buf, 1, 100000, stdin); if (S == T) return EOF; } return *S++; } template<typename T> inline void read(T &x) { static char c; x = 0; int sgn = 0; for (c = get(); c < '0' || c > '9'; c = get()) if (c == '-') sgn = 1; for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0'; if (sgn) x = -x; } namespace trie { int tcnt; int ch[M][2]; int rt , tag[M], sz[M]; inline void mark(int u, int x, int d) { if (d < 0 || !u) return; tag[u] ^= x; if (x >> d & 1) swap(ch[u][0], ch[u][1]); } inline void pushUp(int u) { sz[u] = sz[ch[u][0]] + sz[ch[u][1]]; } inline void pushDown(int u, int d) { if (tag[u]) { mark(ch[u][0], tag[u], d - 1); mark(ch[u][1], tag[u], d - 1); tag[u] = 0; } } inline void _insert(int &u, int x, int d) { if (!u) u = ++tcnt; if (d < 0) { sz[u] = 1; return; } pushDown(u, d); _insert(ch[u][x >> d & 1], x, d - 1); pushUp(u); } inline int _merge(int x, int y, int d) { if (!x || !y) return x ? x : y; if (d < 0) { sz[x] |= sz[y]; return x; } pushDown(x, d); pushDown(y, d); ch[x][0] = _merge(ch[x][0], ch[y][0], d - 1); ch[x][1] = _merge(ch[x][1], ch[y][1], d - 1); pushUp(x); return x; } inline void mark(int id, int x) { mark(rt[id], x, K); } inline void insert(int id, int x) { _insert(rt[id], x, K); } inline void merge(int from, int to) { rt[to] = _merge(rt[from], rt[to], K); } inline int mex(int id) { int res = 0, u = rt[id]; for (int d = K; ~d; d--) { pushDown(u, d); int dir = (sz[ch[u][0]] == (1 << d)); res |= dir << d; u = ch[u][dir]; } return res; } inline void reset(int n) { for (int i = 1; i <= tcnt; i++) { ch[i][0] = ch[i][1] = 0; tag[i] = sz[i] = 0; } for (int i = 1; i <= n; i++) rt[i] = 0; tcnt = 0; } } int test, n, m, ans, gcnt, x, y; struct edge { int to, next; edge(int t = 0, int n = 0): to(t), next(n) {} }; edge G[N << 1]; int head , sg , vis ; inline void addEdge(int from, int to) { G[++gcnt] = edge(to, head[from]); head[from] = gcnt; G[++gcnt] = edge(from, head[to]); head[to] = gcnt; } inline void dfs(int u, int f) { int to, sum = 0; vis[u] = 1; for (int i = head[u]; i; i = G[i].next) { to = G[i].to; if (to == f) continue; dfs(to, u); sum ^= sg[to]; } for (int i = head[u]; i; i = G[i].next) { to = G[i].to; if (to == f) continue; trie::mark(to, sum); trie::merge(to, u); } trie::insert(u, sum); sg[u] = trie::mex(u); trie::mark(u, sg[u]); } int main(void) { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); read(test); while (test--) { read(n); read(m); ans = gcnt = 0; for (int i = 1; i <= n; i++) sg[i] = head[i] = vis[i] = 0; for (int i = 1; i <= m; i++) { read(x); read(y); addEdge(x, y); } for (int i = 1; i <= n; i++) { if (vis[i]) continue; dfs(i, 0); ans ^= sg[i]; } if (ans) printf("Alice\n"); else printf("Bob\n"); trie::reset(n); } return 0; }
相关文章推荐
- [博弈 & 字典树合并] BZOJ4730. Alice和Bob又在玩游戏
- 【bzoj4730】 Alice和Bob又在玩游戏
- bzoj 4730: Alice和Bob又在玩游戏 线段树合并&博弈论
- bzoj4730: Alice和Bob又在玩游戏
- 4730: Alice和Bob又在玩游戏
- 字典树合并 ifrog1028 Bob and Alice are playing numbers
- hdu 4111 Alice and Bob(博弈)
- ZOJ 3666 Alice and Bob(博弈)
- [博弈] hdu 4371 alice and bob
- Alice and Bob (SG函数)
- ZOJ 3529 A Game Between Alice and Bob(博弈论-sg函数)
- [UVALive5760] Alice and Bob && 博弈
- 2016BIT小学期——博弈DP(污神Alice和Bob)
- ZOJ 3529 A Game Between Alice and Bob(博弈论-sg函数)
- 【博弈】Alice and Bob CodeForces - 347C
- ZOJ 3529 A Game Between Alice and Bob(博弈论-sg函数)
- hrbust 2203 Alice and Bob(规律 博弈)
- 【2016杭电女生赛1007】【博弈 打表找规律】Alice and Bob 可走k步斜对角线的胜负态
- HDU 4111 Alice and Bob (博弈[记忆话搜索])
- Alice and Bob(博弈)