树状数组可以看作线段树的变形,不同于线段树可以计算区间和,区间最大/最小值,树状数组一般只能完成以下操作:
给定一个初始值全为0的数列
- 给定,计算,即前缀和
- 给定和,执行。
基于线段树的实现
如果使用线段树执行上述功能,只需要对介绍过的RMQ进行少量的修改,就可以实现,线段树每个节点维护区间的和。
接下来,我们重点关注给定区间始末,如何求得,对于线段树,我们直接进行区间的迭代查询即可。但是有时这个效率依然是不够的
此时,如果我们维护前缀和,那么只需要计算即可。在这样的限制下在这样的思路下,对线段树进行改造,会让他发生什么变化呢?我们会发现,线段树所有右儿子的值我们都不在需要进行维护
有了的前缀和相当于和的前缀和相当于,我们就不再需要的前缀和,因为$sum[3]-sum[1]就是2-3的和。基于这种思路得到的数据结构就是BIT(Binary Indexed Tree)。
BIT
所谓BIT就是把线段树中不需要的节点去掉之后,再把剩下的节点对应到数组中。让我们对比每个节点对应的区间的长度和节点编号的二进制表示。以1结尾的1,3,5,7的长度是1,最后有1个0的2,6 的长度是2, 最后有2个0的4的长度是4……这样,编号的二进制表示就能够和区间非常容易地对应起来。利用这个性质,BIT可以通过非常简单的位运算实现。
BIT的求和
计算前项的和需要从开始,不断把当前位置的值加到结果中,并从i中减去的二进制最低非0位对应的幂,直到变成0为止。二进制的最后一个1可以通过得到。解释一下,计算机内二进制存储形式是补码,正数变负数,补码的话是最后一个非零位不变,这之前的所有位取反,因此正数与他相反数的与就是最后一个非零位的权值。
BIT值的更新
使第项的值增加要从开始,不断把当前位置的值增加,并把的二进制最低非0位对应的幂加到上。也就是说要更新他和他所有的父节点。
BIT的实现
来源:CSDN
作者:csyifanZhang
链接:https://blog.csdn.net/csyifanZhang/article/details/104572301