举例子:
插入cat:
插入cup:
插入soup:
插入cut:
可持久化数据结构的重要问题就是解决区间的查询问题:
例题,洛谷4735:
M个操作,
操作1:添加操作,添加一个树x,序列长度+1
操作2:询问操作,找到一个位置p,满足l<=p<=r,使得a[p] ^ a[p+1] ^ ... ^ a[N] ^ x 最大,输出最大值
分析:
令S[k] = a[1] xor a[2] xor ... xor a[k]
a[p] xor a[p+1] xor ... xor a[N] xor x
=(a[1] xor a[2] xor ... xor a[p-1]) xor (a[1] xor a[2] xor ... xor a[N]) xor x
=s[p-1] xor s[N] xor x
(p = 1时,a[1] xor a[2] xor ... xor a[N] xor x = s[0] xor s[N] xor x,所以s[0] = 0)
又因为s[N] xor x是定值,设为v
此时查询转变为:求一个p∈[l-1,r-1] 使得 s[p] ^ x 最大
思路:
构建一个可持久化0/1Trie树,第i个版本为插入了s[i]后的Trie树
每次查询,从根节点开始,贪心地选与这一位相反的值
先考虑查询[1,r]的区间,即查询[0,r-1]的区间,只需要拿出版本为r-1的Trie树,按照上面的贪心方法,即可得到[0,r-1]区间内与定值v的异或最大值
再考虑查询[l,r]的区间,即查询[l-1,r-1]的区间,依然可以拿出版本为r-1的Trie树,查询的时候尽量向着相反的方向跳,但不能超过左侧边界l-1,对每个节点维护一个ver,
ver[i]表示第一次被创建的版本。这样,在查询时只访问ver>=l−1的节点就行了。
ver[0]代表所有的不能走的空结点,因为不能走,所以要比最小的l-1(0)要小,这样就会在判断l-1时条件时候避免走空结点,设为-1