Description
给定一个非负整数序列 $\{a\}$,初始长度为 $N$ 。
有 $M$ 个操作,有以下两种操作类型:
A x
:添加操作,表示在序列末尾添加一个数 $x$,序列的长度 $N+1$ 。
Q l r x
:询问操作,你需要找到一个位置 $p$,满足 $l \le p \le r$,使得 $a_p \oplus a_{p+1} \oplus \cdots \oplus a_N \oplus x$ 最大,输出最大是多少。
$(1 \leq N,M \leq 3 \times 10^5,0 \leq a_i \leq 10^7)$
Source
Solution
先考虑简化问题。
我们可以像前缀和一样预处理出 $pre_i = a_1 \oplus a_2 \oplus \cdots \oplus a_i$,再根据异或运算的性质,可以得到:
问题就变为找到一个位置 $p - 1$,满足 $l - 1 \le p - 1 \le r - 1$,使得 $pre_n \oplus pre_{p - 1} \oplus x$ 最大。显然 $pre_n$ 和 $x$ 都已知,所以我们只需要找与 $x \oplus pre_n$ 在指定范围内且异或结果最大的 $pre_{p - 1}$ 即可。
看到这个问题,很容易想到用 0-1 Trie 来维护。但是因为限制了区间,一棵 Trie 是肯定不够用的,所以还要 可持久化 。
可持久化 Trie 和 主席树 的实现方法相似。我们每插入一个前缀异或和 $pre_i$,就建一棵 Trie 。由于第 $i$ 棵 Trie 与第 $i - 1$ 棵 Trie 最多只会有 $\log n$ 棵节点是不同的。所以插入时,我们只需要新建一个根,只对当前数的每一位新建节点,其余的点连向上一棵树。这样空间复杂度可以优化为 $O(n \log n)$ 。在上述插入的过程中,我们只需要记录第 $i$ 棵 Trie 每个节点的个数,就能判断一个区间内是否有该节点。查询也很容易,从第 $l - 2$ 与第 $r - 1$ 棵 Trie 的根开始(因为这两棵 Trie 之间的数为 $pre_{l - 1} \sim pre_{r - 1}$),判断是否存在与 $x$ 某一位取反的节点,具体过程类似 [LOJ]10050 。不要忘记在第 $0$ 棵 Trie 上插入 $0$,时间复杂度为 $O(n \log n)$ 。
Code
1 |
|