Fenwick Tree(Binary Indexed Tree) - 树状数组(二进制索引树)
树状数组(二进制索引树)
给定个数字,求区间(其中)上的所有成员之和(简称区域和/区间和)
其中。该区间可以修改任意元素的值。
区间上任意位置的值可以修改,但所有元素都恒为非负整数。
循环累加数组的算法和Segment Tree算法都可以解决该问题,Fenwick树(树状数组/二进制索引树)与Segment Tree同样在时间复杂度内求出某个区域上的和,但空间复杂度更低。实际上由于字节操作,FenwickTree不但占用内存少,且速度更快(内存更紧凑的软件速度更快)。
设,那么的区间和可以表示为。本问题可以转化为求区间上前个元素之和的问题。
任意非负整数都可以表示为的次方和,比如。所以任意非负整数可以用一个代表bit的数组表示:,,,即二进制数字。那么区域可以用个二进制数组来表示所有数字,用Fenwick树结构来表示:
引入最低有效位lowbit函数来构造Fenwick树上的每个节点。是一个非负整数的二进制数字中,最低的非位的数字(比如,显然奇数有):
令Fenwick树上的节点存储值
比如
那么Fenwick树上每个节点覆盖到的区域和如图所示:
设数字用的次方和表示为:
比如。那么恰好有
求非负整数的最低有效位分为以下几步:
减使的最低有效位变为0(),最低有效位之前的那些变为,比如;
然后异或操作()就可以将的最低有效位及之前的所有位设置为,比如;
最后与原做与操作(),结果即为最低有效位对应的数字;
lowbit函数的C++实现如下
int LowBit(int x) {
return x & (x ^ (x-1));
}
或者利用反码特性实现
int LowBit(int x) {
return x & (-x);
}
对于长度为的区域,构造Fenwick树的时间复杂度为,查询区域和的时间复杂度为,修改区域上一个值的时间复杂度为,空间复杂度为。
二进制索引树
- http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=07BA8E50FC6C41AAE5CFCE28AEB9656E?doi=10.1.1.14.8917&rep=rep1&type=pdf
- https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/