这篇文章主要介绍了 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) `代码` - 列表 > 引用。你还可以使用@来通知其他用户。