Codeforces #430 Div2 D

#430 Div2 D

题意

给出一些数,每次操作先将所有数异或一个值,再求这些数中没有出现过的最小的非负整数。

分析

对于更新操作,对于 \(x\) 所有为 \(1\) 的位给相应层添加一个标记,当查询时走到这一层,如果有这个标记,就要把左子树当作右子树,右子树当做左子树。
对于查询操作,显然优先走左子树,如果左子树已经满了,才走右子树,并且答案就要加上对应的层的值,如果发现无路可走,说明后面可以全部取\(0\)了。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 1e6 + 100;
struct Trie {
    int val[MAXN], nxt[MAXN][2], L, root, siz[MAXN], flg[21];
    int newnode() {
        memset(nxt[L], -1, sizeof nxt[L]);
        return L++;
    }
    void init() {
        L = 0;
        root = newnode();
    }
    void insert(int x) {
        int now = root;
        for(int i = 20; i >= 0; i--) {
            int o = ((x >> i) & 1);
            if(nxt[now][o] == -1) {
                nxt[now][o] = newnode();
            }
            now = nxt[now][o];
            siz[now]++;
        }
    }
    void update(int q) {
        for(int i = 20; i >= 0; i--) {
            if((q >> i) & 1) {
                flg[i] ^= 1;
            }
        }
    }
    int query() {
        int now = root;
        int ans = 0;
        for(int i = 20; i >= 0; i--) {
            int o = 0;
            if(flg[i]) o = !o;
            if(nxt[now][o] == -1) {
                break;
            } else {
                if(siz[nxt[now][o]] < (1 << i)) {
                    now = nxt[now][o];
                } else {
                    ans |= (1 << i);
                    if(nxt[now][!o] == -1) break;
                    else now = nxt[now][!o];
                }
            }
        }
        return ans;
    }
}trie;
set<int> num;
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i = 0; i < n; i++) {
        int x;
        cin >> x;
        num.insert(x);
    }
    trie.init();
    for(int i : num) {
        trie.insert(i);
    }
    while(m--) {
        int q;
        cin >> q;
        trie.update(q);
        cout << trie.query() << endl;
    }
    return 0;
}
posted @ 2017-08-30 19:04  ftae  阅读(86)  评论(0编辑  收藏  举报