constint N = 1e5+10; int tree[N][26], cnt[N], idx; char x[N];
voidinsert(char* str){ int p = 0; for (int i = 0; str[i]; i++) { int k = str[i] - 'a'; if (!tree[p][k]) tree[p][k] = ++idx; p = tree[p][k]; } cnt[p]++; }
intfind(char* str){ int p = 0; for (int i = 0; str[i]; i++) { int k = str[i] - 'a'; if (tree[p][k] == 0) return0;
p = tree[p][k]; } return cnt[p]; }
intmain(){ int n; char op[2]; scanf("%d", &n); while (n--) { scanf("%s%s", op, x); if (*op == 'I') insert(x); elseprintf("%d\n", find(x)); } return0; }
voidinsert(int a){ int p = 0; for (int i = 30; i >= 0; --i) { int b = (a >> i) & 1; if (!tree[p][b]) tree[p][b] = ++idx; p = tree[p][b]; } }
intfind(int a){ int p = 0, res = 0; for (int i = 30; i >= 0; --i) { int b = (a >> i) & 1; if (tree[p][!b]) { res = res * 2 + !b; p = tree[p][!b]; } else { res = res * 2 + b; p = tree[p][b]; } } return res; }
intmain(){ int n, a, res = 0; scanf("%d", &n); while (n--) { scanf("%d", &a); insert(a); res = max(res, find(a) ^ a); } printf("%d\n", res); return0; }
寻找的时候从高位到低位,尽量使每一位都不同,但是如果没有只能退而求其次了。其中,res * 2 + b 也可以是 res << 1 + b,但我这样写时间也没什么显著的变化,反而还多花了一点时间。至于这两个写法等价的原因如下:
a2a=i=0∑N(bi⋅2i)=i=0∑N(bi⋅2i+1)=a≪1
其中 bi 代表相应位置上的二进制位。
最大异或和
给定一个非负整数序列 a,初始长度为 N。
有 M 个操作,有以下两种操作类型:
A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N 增大 11。
Q l r x:询问操作,你需要找到一个位置 p,满足 l≤p≤r,使得:a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出这个最大值。
intquery(int u, int c, int l){ for (int i = 23; i >= 0; i--) { int v = c >> i & 1; if (latest[tr[u][v^1]] >= l) u = tr[u][v^1]; else u = tr[u][v]; } return c^s[latest[u]]; }
intmain(){ int n, m; scanf("%d%d", &n, &m); latest[0] = -1; root[0] = ++idx; insert(0, 23, 0, root[0]); for (int i = 1; i <= n; i++) { int v; scanf("%d", &v); s[i] = s[i-1] ^ v; root[i] = ++idx; insert(i, 23, root[i-1], root[i]); } while (m--) { char op[2]; scanf("%s", op); if (*op == 'A') { int x; scanf("%d", &x); n++; root[n] = ++idx; s[n] = s[n-1]^x; insert(n, 23, root[n-1], root[n]); } else { int l, r, x; scanf("%d%d%d", &l, &r, &x); printf("%d\n", query(root[r-1], s[n]^x, l-1)); } } return0; }