Fenwick树与段树

Wil*_*nga 12 algorithm tree fenwick-tree segment-tree

我需要计算数组范围内的总和,所以我遇到了 Segment Tree 和 Fenwick Tree,我注意到这两种树都以相同的渐近运行时间进行查询和更新。我做了更多的研究,这两种数据结构似乎以相同的速度完成所有事情。两者都具有线性内存使用量(段树使用量是其两倍)。

除了运行时间/内存和实现中的恒定因素之外,还有什么理由让我选择一个而不是另一个?

我正在寻找一个客观的答案,例如某些操作比另一个更快,或者可能某个限制另一个没有。

我看到了另外 2 个关于此的 StackOverflow 问题,但答案只是描述了这两种数据结构,而不是解释何时一个可能比另一个更好。

Shr*_*rni 22

在 Quora 上读到了这个。希望你觉得它有用。

  1. 有些事情是段树可以做的,但 BIT 不能:BIT 本质上与累积数量一起工作。当需要区间 [i..j] 的累积量时,可以找到 [1...j] 和 [1...i-1] 的累积量之间的差值。这只是因为加法有一个逆运算。如果操作是不可逆的(例如 max),则无法执行此操作。另一方面,线段树上的每个区间都可以作为不相交区间的并集找到,不需要逆运算
  2. 一个BIT只需要一半的内存段树:在你有自虐内存限制的情况下,你几乎坚持使用位
  3. 虽然 BIT 和段树操作都是 O(log(n)),但段树操作有一个更大的常数因子:这在大多数情况下应该无关紧要。但同样,如果您有自虐的时间限制,您可能希望从段树切换到 BIT。如果 BIT/Segment 树是多维的,那么常数因子可能会成为一个更大的问题。

  • 你一直在谈论双边投资协定,而 OP 则问起芬威克树。BIT 是 Fenwick 树吗?如果是的话就需要说明一下。 (4认同)
  • @user3724404 是的,BIT 和 fenwick 树是同一件事 (4认同)

小智 7

我在cp-Algorithm上找到了一些 可能对你有帮助的东西。

线段树-

  • 在 O(logN) 内回答每个查询
  • 预处理在 O(N) 内完成
  • 优点:时间复杂度好。
  • 缺点:与其他数据结构相比,代码量更大。

芬威克树-

  • 在 O(logN) 内回答每个查询

  • 预处理在 O(NlogN) 内完成

  • 优点:代码最短,时间复杂度好

  • 缺点:Fenwick树只能用于L=1的查询,因此不适用于很多问题。

  • 芬威克树的构建时间复杂度为 O(N)。不要对每个条目调用 update,而是迭代每个元素并将数组的值更新为直接父元素。我们还可以通过计算 R 和计算出的 L 的反函数来使用 L != 1 的 Fenwick 树。即,如果求和是函数,那么您找到 R 和 L 并从 R 中减去 L 的结果即可得到答案。 (11认同)
  • 你提到的这个 L ni L = 1 是什么? (3认同)

小智 5

对 Harsh Hitesh Shah 答案的评论:反对使用 Fenwick 树的最后一点通常不成立。通过反例证明:假设我们有一个用于前缀和的 Fenwick 树,函数 query(x) 返回从第一个索引 1 开始到包括索引 x 的前缀和。如果我们想计算某个区间 [L, R] 的总和,且 1 < L <= R <= N,我们可以采用 query(R)-query(L-1)。