Description
Solution
review 一下异或的 trick
a
⊕
b
⊕
c
=
a
⊕
(
b
⊕
c
)
a \oplus b \oplus c =a \oplus(b \oplus c)
a⊕b⊕c=a⊕(b⊕c)
a ⊕ b ⊕ b = a a \oplus b \oplus b = a a⊕b⊕b=a
对于没有加操作的时候,可以维护一个异或的懒标记,当有异或操作的时候懒标记 t a g ⊕ x tag \oplus x tag⊕x,插入删除时,对应将 x ⊕ t a g x \oplus tag x⊕tag 插入或删除,再最后输出的时候将每一项 ⊕ t a g \oplus tag ⊕tag。
考虑加法操作。由于只加一,可以从二进制入手。找规律发现一个数 k k k 的二进制位数为 ⌊ l o g 2 ( k ) ⌋ + 1 \lfloor log_2(k) \rfloor + 1 ⌊log2(k)⌋+1,我们令一个数的最低位到最高位依次为 a 1 ∼ a 30 a_1 \sim a_{30} a1∼a30,那么 + 1 m o d 2 30 +1 \bmod 2^{30} +1mod230 为找到一个满足 a i = 0 a_i = 0 ai=0 且 a 1 ∼ a i − 1 = 1 a _ 1 \sim a_ {i - 1} = 1 a1∼ai−1=1,然后把 1 1 1 变成 0 0 0, 0 0 0 变成 1 1 1,如果不存在满足条件的 i i i,那么认为 i = 31 i = 31 i=31,那么需要把所有的 a i a_i ai 都反转成 0 0 0。
按照插入数字从低到高维护一棵字典树,用 v a l x val_x valx 表示字典树节点 x x x 对应值出现的次数为 v a l x val_x valx,那么插入和删除操作就是对应的 + 1 +1 +1 或 − 1 -1 −1, + 1 +1 +1 就是 + t a g +tag +tag, 输入时就直接插入。当找到了满足条件的 i i i 时,反转相当于交换 i i i 的左右儿子。
get 了 trie 的神奇用法。
Code
#include <bits/stdc++.h>
using namespace std;
#define re register
#define F first
#define S second
typedef long long ll;
typedef pair<int, int> P;
const int N = 6e6 + 5;
const int INF = 0x3f3f3f3f;
int read() {
int x = 0, f = 0; char ch = 0;
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
int n, q, tag, ch[N][2], val[N], ans[N], cnt, tot = 1;
void insert(int k){
int p = 1;
for (int i = 0; i < 30; i++, k >>= 1){
int c = k & 1;
if(!ch[p][c]) ch[p][c] = ++tot;
p = ch[p][c];
}
val[p]++;
}
void erase(int k){
int p = 1;
for (int i = 0; i < 30; i++, k >>= 1) p = ch[p][k & 1];
val[p]--;
}
void add(int k){
int p = 1;
for (int i = 0; i < 30; i++, k >>= 1){
swap(ch[p][0], ch[p][1]);
p = ch[p][k & 1];
}
}
void dfs(int x, int dep, int p){
if(dep == 30){
for (int i = 1; i <= val[x]; i++) ans[++cnt] = p ^ tag;
return ;
}
if (ch[x][0]) dfs(ch[x][0], dep + 1, p);
if (ch[x][1]) dfs(ch[x][1], dep + 1, p | (1 << dep));
}
int main(){
n = read(), q = read();
for (int i = 1; i <= n; i++){
int x = read(); insert(x);
}
while (q--){
int opt = read(), x;
if(opt != 3) x = read();
if(opt == 1) insert(x ^ tag);
if(opt == 2) erase(x ^ tag);
if(opt == 3) add(tag);
if(opt == 4) tag ^= x;
}
dfs(1, 0, 0);
sort(ans + 1, ans + cnt + 1);
for (int i = 1; i <= cnt; i++) printf("%d ", ans[i]);
return 0;
}