把后缀异或改写为前缀异或区间查询,用可持久化 01-Trie 支持追加与最大异或。
OJ: luogu
题目 ID: P4735
难度:省选/NOI-
标签:可持久化Trie前缀异或在线追加python
日期: 2026-07-16 19:57
题意
序列支持末尾追加。询问在 l <= p <= r 中最大化 a[p] ^ ... ^ a[N] ^ x。
思路
令 s[i] 为前 i 项异或,则询问式为:
text
s[p-1] ^ (s[N] ^ x)所以要在前缀下标 [l-1,r-1] 中找与固定值异或最大的 s。每加入一个前缀异或,就从旧根复制 24 层路径得到新版本;未修改的子树直接共享。
约定 roots[t] 包含前缀下标 0..t-1。因此查询区间使用 roots[r] - roots[l-1] 的节点计数差。每一位优先进入能让异或位为 1 且差分计数大于 0 的儿子。
Python 知识
operation = input().split()保留首项为bytes,可直接与b"A"比较。clone同步复制三个紧凑数组中的一个节点。array("i")的节点下标和计数足够容纳约 1500 万节点,内存远低于嵌套列表对象。- 当前总前缀异或只需一个整数变量随追加更新。
代码
python
import sys
from array import array
MAX_BIT = 23
input = sys.stdin.buffer.readline
n, operation_count = map(int, input().split())
initial = map(int, input().split())
left = array("i", [0])
right = array("i", [0])
count = array("i", [0])
def clone(node):
left.append(left[node])
right.append(right[node])
count.append(count[node])
return len(count) - 1
def insert(previous_root, value):
root = clone(previous_root)
count[root] += 1
previous, current = previous_root, root
for bit in range(MAX_BIT, -1, -1):
if value >> bit & 1:
child = clone(right[previous])
right[current] = child
previous = right[previous]
else:
child = clone(left[previous])
left[current] = child
previous = left[previous]
current = child
count[current] += 1
return root
def maximum_xor(older_root, newer_root, value):
answer = 0
for bit in range(MAX_BIT, -1, -1):
if value >> bit & 1:
wanted_old, wanted_new = left[older_root], left[newer_root]
other_old, other_new = right[older_root], right[newer_root]
else:
wanted_old, wanted_new = right[older_root], right[newer_root]
other_old, other_new = left[older_root], left[newer_root]
if count[wanted_new] > count[wanted_old]:
answer |= 1 << bit
older_root, newer_root = wanted_old, wanted_new
else:
older_root, newer_root = other_old, other_new
return answer
roots = array("i", [0])
prefix_xor = 0
roots.append(insert(0, 0))
for value in initial:
prefix_xor ^= value
roots.append(insert(roots[-1], prefix_xor))
answers = []
for _ in range(operation_count):
operation = input().split()
if operation[0] == b"A":
prefix_xor ^= int(operation[1])
roots.append(insert(roots[-1], prefix_xor))
else:
left_index, right_index, value = map(int, operation[1:])
value ^= prefix_xor
answers.append(str(maximum_xor(roots[left_index - 1], roots[right_index], value)))
print("\n".join(answers))复杂度
每次追加和询问都处理 24 位,时间
总结
先把后缀式改写成前缀异或,再用版本差表达下标范围,是可持久化 01-Trie 的标准模型。