-
用 root[⋯] 数组来定位每个根节点,不妨设 trie 中字符集合为 C,全体字符集为 A
当前插入第 i 个字符串,即执行第 i 个版本,p←root(i−1) -
新建一个节点 q,即 q=root(i)=++tot,假设当前插入字符 Sj
-
如果 p≠0,对于 ∀c∈{C}, c≠Sj,令 t(q,c)←t(p,c)
(这一步可以检查 ∀c∈{A} 全体字符集,令 t(q,c)←t(p,c),因为下一步 t(q,Sj) 会重新定位到新开的节点上) -
新建一个节点,令 t(q,Sj)=++tot,即除了 Sj 指针不同外,p,q 的其余信息完全相同
-
p←t(p,Sj),q←t(q,Sj),j←j+1 直到字符串结尾
-
可以类似引入一个异或前缀和的概念
n⨁i=pap=Sn⊕Sp−1
-
对于添加操作,很简单 Sn+1=Sn⊕x, n=n+1
-
如果令 p′=p−1, l−1⩽,询问操作实际上就是令 val = x \oplus S_n
求一个位置 p,满足 l-1 \leqslant p \leqslant r-1,使得 S_p \oplus val 最大
这个问题如果没有 p \in [l-1, r-1] 的限制,就是最大异或和问题 -
对于 p \leqslant r-1,可以借鉴主席树思想,对 \text{trie} 进行可持久化,在第 r-1 个版本
即 \text{root}(r-1) 中查询最大异或和路径
(p = \text{root}(r-1),从高位到低位尽可能沿着和 val 相反的位走) -
对于 p \geqslant l-1,只要保证异或和路径上所经过点的时间戳 \geqslant l-1 即可
对于插入操作 \text{insert}(pre, p, i) 表示插入第 i 个字符串
k 从高位到低位遍历,此时第 k 位的字符为 c = S_i >> k \& 1 -
如果 pre \neq 0,令 t(p, c\oplus 1) \leftarrow t(pre, c\oplus 1)
-
t(p, c) = ++tot,于此同时标记节点时间戳 dfn(p) = i,然后和主席树一样同步往下走
p \leftarrow t(p, c), \ pre \leftarrow t(pre, c), \textbf{then} \ dfn(p) = i
const int N = 600000 + 5;
const int maxn = N * 25;
int n, m, s[N], root[N];
class Trie {
public:
int t[maxn][2], dfn[maxn];
int tot;
Trie() {
tot = 0;
memset(t, 0, sizeof 0);
memset(dfn, 0, sizeof 0);
dfn[0] = -1;
}
void insert(int pre, int p, int ver) {
dfn[p] = ver;
for (int k = 25; k >= 0; k--) {
int c = s[ver] >> k & 1;
if (pre) t[p][c^1] = t[pre][c^1];
t[p][c] = ++tot;
p = t[p][c], pre = t[pre][c];
dfn[p] = ver;
}
}
int ask(int p, int val, int lim) {
for (int k = 25; k >= 0; k--) {
int c = val >> k & 1;
if (dfn[ t[p][c^1] ] >= lim) p = t[p][c^1];
else p = t[p][c];
}
return s[dfn[p]] ^ val;
}
} trie;
int main() {
freopen("input.txt", "r", stdin);
cin >> n >> m;
// init
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
s[i] = s[i-1] ^ x;
root[i] = ++trie.tot;
trie.insert(root[i-1], root[i], i);
}
while (m--) {
char cmd[2];
scanf("%s", cmd);
if (cmd[0] == 'A') {
int x;
scanf("%d", &x);
root[++n] = ++trie.tot;
s[n] = s[n-1] ^ x;
trie.insert(root[n-1], root[n], n);
}
else {
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
int res = trie.ask(root[r-1], s[n]^x, l-1);
printf("%d\n", res);
}
}
}
您题解的代码是wa的,谢谢
没学过主席树 看不懂咋您这个代码咋wa的最后一个样例
图很好,谢谢力
max_id[0] = -1不这样赋值的话什么情况下会出现问题?