树状数组

生来就可爱ヽ(ⅴ<●) 提交于 2020-03-02 10:17:05

树状数组可以看作线段树的变形,不同于线段树可以计算区间和,区间最大/最小值,树状数组一般只能完成以下操作:

给定一个初始值全为0的数列a1...ana_1...a_n

  • 给定ii,计算a1+a2+...+aia_1+a_2+...+a_i,即前缀和
  • 给定iixx,执行ai+=xa_i+=x

基于线段树的实现

如果使用线段树执行上述功能,只需要对介绍过的RMQ进行少量的修改,就可以实现,线段树每个节点维护区间的和。
在这里插入图片描述
接下来,我们重点关注给定区间始末s,ts,t,如何求得as+as+1+...+ata_s+a_{s+1}+...+a_t,对于线段树,我们直接进行区间的迭代查询即可。但是有时这个效率依然是不够的

此时,如果我们维护前缀和sum[i]=a0+...+aisum[i]=a_0+...+a_i,那么只需要计算sum[t]sum[s]sum[t]-sum[s]即可。在这样的限制下在这样的思路下,对线段树进行改造,会让他发生什么变化呢?我们会发现,线段树所有右儿子的值我们都不在需要进行维护
在这里插入图片描述
有了[03][0-3]的前缀和相当于sum[3]sum[3]010-1的前缀和相当于sum[1]sum[1],我们就不再需要[23][2-3]的前缀和,因为$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的求和

在这里插入图片描述
计算前ii项的和需要从ii开始,不断把当前位置ii的值加到结果中,并从i中减去ii的二进制最低非0位对应的幂,直到ii变成0为止。ii二进制的最后一个1可以通过i&ii\&-i得到。解释一下,计算机内二进制存储形式是补码,正数变负数,补码的话是最后一个非零位不变,这之前的所有位取反,因此正数与他相反数的与就是最后一个非零位的权值。

BIT值的更新

使第ii项的值增加xx要从ii开始,不断把当前位置ii的值增加xx,并把ii的二进制最低非0位对应的幂加到ii上。也就是说要更新他和他所有的父节点。
在这里插入图片描述

BIT的实现

在这里插入图片描述

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!