考虑这么一个题目:

维护整数多重集,支持插入删除,查询全局 xor 和以及全局加一。


如果不考虑全局加一,就是唐题。不过全局加一和异或本质不兼容,比较难搞。

本文介绍的就是用以解决这一问题的技巧。


考虑维护一棵 01 Trie。与普通的用于按位贪心的 Trie 不同,这棵 Trie 按照从低位往高位的顺序。

简单来说,根节点是从低往高第 0 位,是一个超级源点。它的两个孩子是从低往高第 1 位,位权为 1,这两个孩子的孩子(即深度为 2 的那一层节点)的位权为 2,以此类推。

插入、删除和普通 01 Trie 相同。

查询全局 xor 和也比较好做。我们在每个节点上维护 count(子树中的元素计数)和 xor_sum(子树中元素的异或和)。

加法是重点。

注意到最低位为 0 的元素加一之后最低位为 1,而最低位为 1 的元素加一之后最低位为 0,并产生一个进位。

那么从根节点出发,先交换两个儿子,然后递归操作那个本次操作前当前位为 1 的子树。

结束了。


扩展:全局异或上一个数

考虑维护全局懒标记:Trie 中的一个值 v 的实际值是 v xor tag。

全局异或就变成了对 tag 的简单更新。

现在考虑如何在有 tag 的情况下做全局加一。

很简单:套用之前交换子树和递归进位的逻辑。不过,注意 Trie 中当前位为 1 的子树未必是真实产生进位的子树,因为 tag 的当前位可能为 1,这时,Trie 中的 1 子树的真实值为 0,反而是 0 子树的真实值为 1。