树状数组

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

给定一个初始值全为0的数列 a 1 . . . a n a_1...a_n a1...an

  • 给定 i i i,计算 a 1 + a 2 + . . . + a i a_1+a_2+...+a_i a1+a2+...+ai,即前缀和
  • 给定 i i i x x x,执行 a i + = x a_i+=x ai+=x

基于线段树的实现

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

此时,如果我们维护前缀和 s u m [ i ] = a 0 + . . . + a i sum[i]=a_0+...+a_i sum[i]=a0+...+ai,那么只需要计算 s u m [ t ] − s u m [ s ] sum[t]-sum[s] sum[t]sum[s]即可。在这样的限制下在这样的思路下,对线段树进行改造,会让他发生什么变化呢?我们会发现,线段树所有右儿子的值我们都不在需要进行维护
在这里插入图片描述
有了 [ 0 − 3 ] [0-3] [03]的前缀和相当于 s u m [ 3 ] sum[3] sum[3] 0 − 1 0-1 01的前缀和相当于 s u m [ 1 ] sum[1] sum[1],我们就不再需要 [ 2 − 3 ] [2-3] [23]的前缀和,因为$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 i i项的和需要从 i i i开始,不断把当前位置 i i i的值加到结果中,并从i中减去 i i i的二进制最低非0位对应的幂,直到 i i i变成0为止。 i i i二进制的最后一个1可以通过 i & − i i\&-i i&i得到。解释一下,计算机内二进制存储形式是补码,正数变负数,补码的话是最后一个非零位不变,这之前的所有位取反,因此正数与他相反数的与就是最后一个非零位的权值。

BIT值的更新

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

BIT的实现

在这里插入图片描述

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值