O(log n) 时间的插入可以通过增强的二叉搜索树来实现。存储
order_come | start | end | weight
0 [10, 20] 32
1 [15, 25] 32
2 [5, 30] 32
3 [30, 40] 64
4 [1, 50] 16
5 [1, 60] 16
我们有一棵形状像这样的树
25
/ \
/ \
10 50
/ \ / \
5 20 40 60
/ / /
1 15 30 ,
其中每个数字表示从它到其后继的间隔。与每个树节点相关联的是两个数字。第一个我们称为 Δweight,定义为节点区间的权重减去节点父节点区间的权重,如果范围(否则为零)。第二个我们称为 Δmax,定义为与节点的后代对应的区间的最大权重减去节点的权重。
对于上面的例子,
interval | tree node | total weight | ∆weight | ∆max
[1, 5) 1 32 -32 0
[5, 10) 5 64 -32 0
[10, 15) 10 96 32 32
[15, 20) 15 128 32 0
[20, 25) 20 96 0 32
[25, 30) 25 64 64 64
[30, 40) 30 96 64 0
[40, 50) 40 32 16 64
[50, 60) 50 16 -48 80
[60, ∞) 60 0 -16 0
二叉搜索树操作几乎总是需要旋转。当我们像这样旋转一棵树时
p c
/ \ / \
c r => l p
/ \ / \
l g g r
我们修改
c.∆weight += p.∆weight
g.∆weight += c.∆weight
g.∆weight -= p.∆weight
p.∆weight -= c.∆weight
p.∆max = max(0, g.∆max + g.∆weight, r.∆max + r.∆weight)
c.∆max = max(0, l.∆max + l.∆weight, p.∆max + p.∆weight).
增强的要点如下。要找到树中的最大权重,请计算 r.∆max + r.∆value,其中 r 是根。要将子树中的每个权重增加给定数量 ∂,请将子树根的 Δweight 增加 ∂。通过使用包含-排除更改 O(log n) 节点,我们可以增加整个区间。总之,这些操作允许我们在 O(log n) 时间内评估插入。
要查找区间的总权重,请正常搜索该区间,同时将该区间的祖先的 Δweight 值相加。例如,要找到 [15, 30] 的权重,我们寻找 15,遍历 25(Δweight = 64)、10(Δweight = 32)、20(Δweight = 0)和 15(Δweight = 32),总权重为 64 + 32 + 0 + 32 = 128。
为了找到假设区间内的最大总权重,我们进行了类似这样的修改搜索。使用另一个修改后的搜索,计算小于或等于start 的最大树值(predstart;如果start 是所有树值都大于start,则让predstart = -∞)并将其传递给此maxtotalweight .
maxtotalweight(root, predstart, end):
if root is nil:
return -∞
if end <= root.value:
return maxtotalweight(root.leftchild, predstart, end) + root.∆weight
if predstart > root.value:
return maxtotalweight(root.rightchild, predstart, end) + root.∆weight
lmtw = maxtotalweight1a(root.leftchild, predstart)
rmtw = maxtotalweight1b(root.rightchild, end)
return max(lmtw, 0, rmtw) + root.∆weight
maxtotalweight1a(root, predstart):
if root is nil:
return -∞
if predstart > root.value:
return maxtotalweight1a(root.rightchild, predstart) + root.∆weight
lmtw = maxtotalweight1a(root.leftchild, predstart)
return max(lmtw, 0, root.rightchild.∆max + root.rightchild.∆weight) + root.∆weight
maxtotalweight1b(root, end):
if root is nil:
return -∞
if end <= root.value:
return maxtotalweight1b(root.leftchild, end) + root.∆weight
rmtw = maxtotalweight1b(root.rightchild, end)
return max(root.leftchild.∆max + root.leftchild.∆weight, 0, rmtw) + root.∆weight
我们假设 nil 的 Δweight = 0 和 Δmax = -∞。很抱歉遗漏了所有细节。