码迷,mamicode.com
首页 > 其他好文 > 详细

【清华集训2016】Alice和Bob又在玩游戏

时间:2019-09-21 16:54:26      阅读:97      评论:0      收藏:0      [点我收藏+]

标签:push   swap   turn   ||   include   oid   swa   val   txt   

不难的题目。因为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又在玩游戏

标签:push   swap   turn   ||   include   oid   swa   val   txt   

原文地址:https://www.cnblogs.com/daklqw/p/11563341.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!