van Emde Boas 树
目标:维护\(n\)个值域在\([0,U-1] \cap \mathbb{N}\)中的元素,支持在\(O(\log \log U)\)内实现插入一个元素、删除一个元素、查找某个元素的后继。
(上图为存储16个元素的vEB树结构。最外层是容量为16的块,其由1个容量为4的summary块和4个容量为4的cluster块构成;而每一个容量为4的块都是由1个summary基块和2个cluster基块构成。基块不再分解,其直接存储2个数)
vEB树是树套树结构。每个vEB块由两部分组成,上层的summary块和下层的若干cluster块。递归地,每个块也是一个vEB树。直至大小为2的块不再递归分解,称为vEB基块。称能表示\(m\)个bit的vEB块的容量是\(m\)。
一整棵vEB树的最底层对接的是一个\([0, 1, \cdots, U-1]\)的bit vector(该vector是虚拟的,由最底层的基块们构成)。该vector需要一棵容量为\(U\)的vEB树存储。
一个容量为\(m\)的vEB块由1个summary块和\(\sqrt{m}\)个cluster块构成,两种块的容量都是\(\sqrt{m}\)。其中,cluster块负责递归向下存储真实数据,summary块存储的这\(\sqrt{m}\)个数据分别表示各个cluster块中是否有存储数据(summary块第i位是cluster[i]存储数据的逻辑或)。
每个块同时维护min和max,表示该块对应区间内下标的最小值和最大值。特别地,最小值不直接插入vEB树,作为该块实际存储信息的一部分(即使递归到最底层bit vector里V.min下标的值是0,vEB树依然视为存储了V.min这个值,且V.min对应的下标必须是0而非1)。如果该块仅存储了一个数,那么一定是min有值而底层全为0,不允许出现底层有1但是min是None的情况,同时此时不递归地向下进行赋值,也就是说此时该块下的所有summary和cluster块的min都是None。
max不具备存储能力,它就是一个普通的区间下标max。如果没有元素,则其为None;如果只有一个元素,则其等于min的值。
基块只有min和max,存储能力是2。基块的min和max都表示实际信息,对应值是None表示没有存储,不是None就表示存储了对应值。
建树代码:
class VEBTree: # Build vEB tree
def __init__(self, u):
self.u = u
self.min = None
self.max = None
if u > 2:
self.sqrt_u = int(math.isqrt(u))
self.summary = VEBTree(self.sqrt_u)
self.cluster = [VEBTree(self.sqrt_u)
for _ in range(self.sqrt_u)]
以下记hi(x)表示x对应子块id,lo(x)表示x进入子块后对应id。由于\(x = \text{hi}(x) \cdot \sqrt{V} + \text{lo}(x)\),(\(V\)是当前块的容量)所以二者都可以\(O(1)\)求出。以上面存储16个数的最外层vEB块为例,hi(6)=1, lo(6)=2,表示下标6是第1个子块中第2个元素。(每个块的id都是从0开始的)
用index(i, j)表示从外层来看hi=i, lo=j的下标应该是多少,即\(\text{index}(i, j) = i \cdot \sqrt{V} + j\),用于还原下标。
- 插入
def INSERT(V, x):
if V.min == None:
V.min := x
V.max := x
ret
if x < V.min:
swap(x, V.min) # V.min records x, and the original V.min will be inserted then
if x > V.max:
V.max := x
if V.cluster[hi(x)].min == None:
INSERT(V.summary, hi(x))
INSERT(V.cluster[hi(x)], lo(x))
两个INSERT总恰有一个会递归下去,另一个要么不进入,要么只递归一次就返回了。递推式\(T(u) = T(\sqrt{u}) + O(1)\),于是插入操作是\(O(\log \log U)\)的。
- 删除
def DELETE(V, x):
if x == V.min:
i := V.summary.min
if i == None:
V.min := None
V.max := None
ret
V.min := Index(i, V.cluster[i].min) # save the new global min
x := V.min # fresh the global min in cluster to 0 then
DELETE(V.cluster[hi(x)], lo(x))
if V.cluster[hi(x)].min == None:
DELETE(V.summary, hi(x))
if x == V.max: # updating max
if V.summary.max == None:
V.max := V.min
else:
V.max := Index(V.summary, V.cluster[i].max)
如果要删除的值是全局最小值V.min,那么找到除V.min之外的最小值(如果连这个次小值都找不到那就直接赋None返回),把这个次小值提到V.min里,然后清空原本内层块存储它的1(相当于接着递归下去删除它)。
如果删除后某个cluster从有变空,那么需要把summary中对应值置0。同理,两个DELECT至多只有一个递归深入下去。因为如果前一个深入,则说明内层至少有2个数,不会删空;若后一个深入,则说明内层仅有min存数,只进行一次递归就返回了。满足\(T(u) = T(\sqrt{u}) + O(1)\)的形式,推知\(T(U) = O(\log \log U)\)。
- 查后继
def Successor(V, x):
if x < V.min:
ret V.min
if V.cluster[hi(x)].max != None and lo(x) < V.cluster[hi(x)].max:
i := hi(x)
j := Successor(V.cluster[hi(x)], lo(x))
else:
i := Successor(V.summary, hi(x))
j := V.cluster[i].min
ret Index(i, j)
所有操作时间递推式都满足\(T(u) = T(\sqrt{u}) + O(1)\)的形式,推知\(T(U) = O(\log \log U)\)。

vEB树,利用树套树结构在O(log log U)的时间复杂度内解决值域为U的自然数集插入、删除、查询后继
浙公网安备 33010602011771号