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;
}