树状数组

Posted YXY_1211

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组相关的知识,希望对你有一定的参考价值。

    首先,我们需要了解一下数在计算机中的储存方式。

以68为例,他的二进制是(68)2=1000100. 那么-68呢?因为计算机里的整数采用补码表示(补码是原码取反加一),因此-68实际上是68按位取反,末尾加一以后的结果。如下表(忽略符号位):

原码   1 0 0 0 1 0 0

          ↓

反码   0 1 1 1 0 1 1

         ↓

补码   0 1 1 1 1 0 0

我们把(68)2和(-68)2放在一起看一看:

1 0 0 0 1 0 0

0 1 1 1 1 0 0

发现他们末尾带的0是一样多的。因此lowbit(x)=x&-x.   (&是转换成二进制之后进行与运算;而&&是直接进行与运算)


下面是一个比较经典的树状数组(BIT):

 

↓     ↓     ↓     ↓    ↓     

 lowbit   =   24   23     22   21   20                                  

从图中可以得到以下规律:

1)对于结点i,如果他是左子结点(下左上右),那么他父节点的编号就是i+lowbit(i);如果他是右子节点,那么他父节点的编号就是i-lowbit(i)。(i>=lowbit(i))

2)奇数的lowbit之所以都是1,是因为他们的二进制个位就是1(即因数没有2)。后面的以此类推:2、6、10、14只能整除21,4、12可以整除22……因此他们的lowbit依次是2、3……

在以上规律的基础上,我们新建一个数组C(A是原数组),则易得:

Ci=Ai-lowbit(i)+1+Ai-lowbit(i)+2+……+Ai

举例:C1=A1,C2=A1+A2,C3=A3,C4=A1+A2+A3+A4,……


 接下来是一些应用:

1)求前缀和Si:顺着结点i向上,依次找到i左上侧的每个结点j,每个结点的Cj加起来即为结点i的前缀和(如下图)。

2)更新数据:如果修改了一个Ai,如何计算前缀和Si?顺着结点i向上,依次找到i右上侧的每个结点j,修改每个结点的Cj 即可。

以上是关于树状数组的主要内容,如果未能解决你的问题,请参考以下文章

树状数组的树状数组的经典操作

树状数组模板

数据结构之树状数组从零认识树状数组

树状数组 / 二维树状数组

浅谈树状数组

Bit的树状数组