树状数组详解

为什么要使用树状数组

事实上,树状数组的所有操作均可以使用线段树完成。然而,打个比方,你可以用高精度写完只要你算 \(A + B\) 且结果比较小的题目,但是你不会去写高精度,因为那太麻烦了,而且时间和空间效率都不是很高。而树状数组相对于线段树的优势也就是在时间和空间的优势上,掌握了树状数组与没掌握,在做一些题目时就是 \(AC\)\(TLE\) 的区别了。

树状数组的原理

以单点修改求区间和为例,区间树状数组事实上可以看成是一种特殊的前缀和数组,他的过程是这样的(假设原数组为 \([1,2,3,4,5,6,7,8,9]\) ):

  1. 将数组中的偶数位分离出来 ( \([2,4,6,8]\) )
  2. 每个偶数位的数加上与它相邻的左边一位的数,得到一个新的序列 ( \([3,7,11,15][2,4,6,8]\)
  3. 对新的序列重新进行步骤一至步骤二,直到不能进行操作为止 ( \([3,7,11,15][2,4,6,8]\to [10,26][4,8]\to [34][8]\)
  4. 将原来的奇数位混插回去,得到树状数组 ( \([1,3,3,10,5,11,7,36,9]\)

注:\([a,b][c,d]\) 表示序列中有两个元素 \(a,b\) ,他们在原数组中对应的位置是 \(c,d\)

如果记原数组为 \(A\) ,树状数组为 \(C\) ,从上面的过程我们可以看出(为了方便表述,我们将下标表示为二进制形式):

\(C_{0001} = A_{0001}\ (C_1 = A_{1})\)

\(C_{0010} = A_{0010} + A_{0001}\ (C_{2} = A_1 + A_2)\)

\(C_{0011} = A_{0011}\ (C_{3} = A_3)\)

\(C_{0100} = A_{0100} + A_{0011} + A_{0010} + A_{0001}\ (C_{4} = \sum\limits_{i = 1}^4 A_i)\)

\(C_{0101} = A_{0101}\ (C_{5} = A_5)\)

\(C_{0110} = A_{0110} + A_{0101}\ (C_{6} = A_5 + A_6)\)

\(C_{0111} = A_{0111}\ (C_7 = A_7)\)

\(C_{1000} = C_{1000} + C_{0111} + C_{0110} + C_{0101} + C_{0100} + C_{0011} + C_{0010} + C_{0001}\ (C_8 = \sum\limits_{i = 1}^8 A_i)\)

\(C_{1001} = A_{1001}\ (C_9 = A_9)\)

我们可以发现,\(C_i = \sum\limits_{i = l}^r A_i\),其中 \(r = i\)\(l\)\(i\) 去掉最低位的 \(1\) 再在最低位补 \(1\) 后得到的数,即 \(l = (i\ \&\ (i\ \hat\ \ (i - 1))) + 1\) ,我们给了 \(i\ \&\ (i\ \hat\ \ (i - 1))\) 另外一个名称,即 \(lowbit(i)\) ,它还可以表示为 \(i\ \&\ (-i)\) ,至于为什么,就和计算机中负整数补码有关了,网络上有很多相关资料,在此不做赘述。

再放一张图以帮助理解,蓝色为 \(A\) ,橙色为 \(C\)

1730636-20190715133135357-761467518.png

所以我们现在就理清了树状数组和原数组的关系:\(C_i = \sum\limits_{j = lowbit(i) + 1}^i A_j\)

我们还可以发现 \(lowbit(i)\) 表示的就是 \(i\) 的二进制表示只保留最低位的 \(1\) 的数。

updating……

转载于:https://www.cnblogs.com/lornd/p/11188363.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值