zoukankan      html  css  js  c++  java
  • 【清华集训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") << '
    ';
    		tot = 0; memset(head, 0, n + 1 << 2);
    		memset(vis, 0, n + 1); txt = 0;
    		memset(rts, 0, n + 1 << 2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/daklqw/p/11563341.html
Copyright © 2011-2022 走看看