【BZOJ4730】Alice和Bob又在玩游戏

【题目链接】

  • 点击打开链接

【思路要点】

  • 补档博客,无题解。

【代码】

#include
using namespace std;
#define MAXN	100005
#define MAXP	20000005
#define MAXLOG	20
vector  a[MAXN];
int sg[MAXN], n, m, root[MAXN];
bool visited[MAXN];
struct Segment_Tree {
	int size;
	int lc[MAXP], rc[MAXP], depth[MAXP];
	int tag[MAXP], sum[MAXP];
	int new_node(int dep) {
		size++;
		lc[size] = rc[size] = 0;
		tag[size] = sum[size] = 0;
		depth[size] = dep;
		return size;
	}
	void init() {
		size = 0;
	}
	void pushdown(int pos) {
		int tmp = 1 << depth[pos] - 1;
		if (tag[pos] & tmp) {
			tag[pos] ^= tmp;
			swap(lc[pos], rc[pos]);
		}
		if (lc[pos]) tag[lc[pos]] ^= tag[pos];
		if (rc[pos]) tag[rc[pos]] ^= tag[pos];
		tag[pos] = 0;
	}
	void update(int pos) {
		sum[pos] = sum[lc[pos]] + sum[rc[pos]];
	}
	void insert(int &pos, int value) {
		if (depth[pos] == 0) {
			sum[pos] = 1;
			return;
		}
		pushdown(pos);
		int tmp = 1 << depth[pos] - 1;
		if (tmp & value) {
			if (rc[pos] == 0) rc[pos] = new_node(depth[pos] - 1);
			insert(rc[pos], value ^ tmp);
		} else {
			if (lc[pos] == 0) lc[pos] = new_node(depth[pos] - 1);
			insert(lc[pos], value);
		}
		update(pos);
	}
	void reverse(int pos, int value) {
		tag[pos] ^= value;
		pushdown(pos);
	}
	int merge(int x, int y) {
		if (x == 0) return y;
		if (y == 0) return x;
		if (depth[x] == 0) return x;
		pushdown(x);
		pushdown(y);
		lc[x] = merge(lc[x], lc[y]);
		rc[x] = merge(rc[x], rc[y]);
		update(x);
		return x;
	}
	int get(int pos) {
		if (depth[pos] == 0) return 0;
		pushdown(pos);
		int tmp = 1 << depth[pos] - 1;
		if (sum[lc[pos]] == tmp) return get(rc[pos]) + tmp;
		else return get(lc[pos]);
	}
} ST;
void work(int pos, int fa) {
	visited[pos] = true;
	int now = 0;
	root[pos] = ST.new_node(MAXLOG);
	for (unsigned i = 0; i < a[pos].size(); i++) {
		if (a[pos][i] == fa) continue;
		work(a[pos][i], pos);
		now ^= sg[a[pos][i]];
	}
	ST.insert(root[pos], now);
	for (unsigned i = 0; i < a[pos].size(); i++) {
		if (a[pos][i] == fa) continue;
		ST.reverse(root[a[pos][i]], now ^ sg[a[pos][i]]);
		root[pos] = ST.merge(root[pos], root[a[pos][i]]);
	}
	sg[pos] = ST.get(root[pos]);
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; i++)
			a[i].clear();
		for (int i = 1; i <= m; i++) {
			int x, y;
			scanf("%d%d", &x, &y);
			a[x].push_back(y);
			a[y].push_back(x);
		}
		memset(root, 0, sizeof(root));
		memset(visited, false, sizeof(visited));
		int ans = 0; ST.init();
		for (int i = 1; i <= n; i++)
			if (!visited[i]) {
				work(i, 0);
				ans ^= sg[i];
			}
		if (ans) printf("Alice\n");
		else printf("Bob\n");
	}
	return 0;
}

你可能感兴趣的:(【算法】博弈论,【算法】SG函数,【数据结构】字典树,【算法】线段树合并)