zoukankan      html  css  js  c++  java
  • 树状数组

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

    以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 即可。

  • 相关阅读:
    Python之路第十二天,高级(5)-Python操作Mysql,SqlAlchemy
    Python之路第十二天,高级(4)-Python操作rabbitMQ
    Python之路第十一天,高级(3)-线程池
    day11 消息队列、多线程、多进程、协程
    day10 多进程、多线程(一)
    day09编程之socket
    day08面向对象(二)
    day07面向对象(初级篇)
    day06反射和正则
    day05开发 (字符串格式化和常用模块)
  • 原文地址:https://www.cnblogs.com/YXY-1211/p/7114799.html
Copyright © 2011-2022 走看看