这篇文章主要介绍了 Fenwick 树(二进制索引树),包括其基本操作、构建、优化以及一些扩展应用等方面:
基本操作:
Update(i, v)
:将数组A
中索引i
的元素加上v
,时间复杂度为O(1)
。RangeQuery(i, j)
:计算数组A
中索引[i, j]
范围内元素的和,普通数组实现时间复杂度为O(N)
,通过前缀和优化后可变为O(1)
,但更新前缀和会导致后续索引的前缀和出错。
构建优化:
- 朴素方法是对数组
A
中每个元素进行Update(i, A[i])
,时间复杂度为O(N log N)
。 - 更优的方法是从节点 1 开始,将节点值向上传播,时间复杂度为
O(N)
。
- 朴素方法是对数组
- 更快的范围查询优化:通过在
RangeQuery(i, j)
中停止Query(j)
一旦到达节点小于i
,可稍微加快查询速度,对于N = 2^B
的情况,大约有 5%的速度提升。 - 前缀搜索:通过在 Fenwick 树的黄色树(二进制树)中从顶部节点开始向下走,根据左子树的和与随机数
s
的比较来确定索引,时间复杂度为O(log N)
,此操作较为 obscure。 - 范围更新:通过在
DA
(A
的离散导数)上构建 Fenwick 树,可以实现范围更新和点查询操作,RangeUpdate(i, j, v)
只需改变DA[i]
和DA[j + 1]
,时间复杂度为O(log N)
。 - 范围更新和范围查询:通过构建两个 Fenwick 树,一个处理
RangeUpdate
,一个处理RangeQuery
,借助一些数学推导和技巧实现了范围更新和范围查询的操作,时间复杂度为O(log N)
。 - 其他扩展:Fenwick 树还有很多扩展应用,如返回范围内任意函数而不仅仅是和,文章未详细探讨性能和实现考虑因素,如与缓存的交互等,同时给出了用于 flash 卡片应用的 Fenwick 树库的可运行代码。
总的来说,Fenwick 树是一种高效的数据结构,具有多种实用操作和扩展能力,尽管其实现和原理可能有些复杂,但在某些情况下能提供很好的性能。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。