![ccc38bebb09e46401da87808c3ce70a1.png](https://i-blog.csdnimg.cn/blog_migrate/d24e4983e361fdac96ef1c9f78602663.jpeg)
本文来源于力扣圈子,作者:胡小旭。点击查看原文
力扣leetcode-cn.com树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为 Fenwick 树。其初衷是解决数据压缩里的累积频率(Cumulative Frequency)的计算问题,现多用于高效计算数列的前缀和, 区间和。它可以以
文章先介绍低位运算(lowbit)的基本知识,再提及如何将一个整数划分为
lowbit(低位)运算
比如:
公式
如何计算一个整数
比如
朴素算法需要枚举整数中所有的位,时间复杂度为
为了高效获取二进制表示下所有位是 1 的数值,可以利用
比如
为了得到
代码
C++ 实现
const MAX_N = 1 << 20;
int H[MAX_N + 1];
for (int i = 0; i <= 20; ++i) H[1 << i] = i;
while (cin >> n) {
while (n > 0) {
cout << H[n & -n] << ' ';
n -= n & -n;
}
cout << endl;
}
树状数组
假设整数
那么,可以将区间 [1,n] 划分成
-
-
- ...
-
比如,
利用
C++ 实现
while (x > 0) {
printf("[%d, %d]n" x - lowbit(x) + 1, x);
x -= lowbit(x);
}
树状数组是基于以上思想的数据结构,基本用途是维护序列的前缀和。
那么,假设有序列
![75d9c6bb4bfb466ccd6071b52d8cc157.gif](https://i-blog.csdnimg.cn/blog_migrate/779ce13deb8f598dbab27a04ebada0ba.gif)
此时,以树形结构展开的序列 A 中的每一个节点都对应着树状数组中的一个值。那么这个值为以当前节点为根的子树中所有节点值的总和。
接着,我们看下以树形结构展开的树状数组是什么样的。
![1aede75267ab5d1ed6fb70ab14bcb639.gif](https://i-blog.csdnimg.cn/blog_migrate/cbccceef4d44f50333e42acfd550e985.gif)
Index
代表序列A
中元素的索引,为了方便,以 1 为起点计数Original Value
代表序列A
中的元素值BIT Value(Binary Indexed Tree Value)
代表树状数组中的值Binary bit
代表索引值的二进制形式Low bit
代表索引值的二进制形式下的地位
上图中最大的区别是某些节点中的值发生了变化。这是因为,在以树形结构展开的树状数组中的每一个值代表的是一个区间的总和。这个区间即为我们上述求解的区间,比如一个整数 7,可以将其划分成
比如
再比如
基本操作
树状数组支持两个基本操作——查询前缀和,单点增加。
查询前缀和
在寻求序列 A 的前 n 项的前缀和时,等于
C++ 实现
int query(int x) {
int ans = 0;
for (; x; x -= x & -x) ans += bit[x];
return ans;
}
单点增加
观察父子节点的关系,可以推算出,父节点的索引 parent(i),为其子节点索引值 + 其低位——
C++ 实现
void update(int x, int delta) {
for (; x; x += x & -x) bit[x] += delta;
}
关于查询前缀和与单点增加的计算过程,可以观看下面视频展示的动画。
![d9eb33f49eef8cd5dc5751e5149281ed.gif](https://i-blog.csdnimg.cn/blog_migrate/c9ff8c0285a93a396da0af47cc22d9c3.gif)
树状数组与逆序对
对于一个序列
- 逆序遍历序列
- 利用树状数组的性质,使用
操作获取每一个元素的逆序对数
- 将当前元素更新
到树状数组中
- 循环迭代上述步骤,直到遍历所有元素
C++ 实现
int cnt = 0;
for (int i = A.size() - 1; i >= 0; --i) {
cnt += query(A[i]);
update(A[i], 1);
}
在每一次更新
在每一次获取
注意,上述的求解过程时,如果序列A的值范围较大时,那么需要离散化处理。
参考
- 《算法竞赛进阶指南》
- 维基百科——树状数组
本文作者:胡小旭
声明:本文归作者版权所有,如需转载请联系。文中图片和视频为作者“胡小旭”制作,未经允许严禁修改和翻版使用。