树状数组
来源:互联网 发布:当淘宝店主真的累 编辑:程序博客网 时间:2024/06/08 14:18
对普通数组进行M次修改或求和,时间复杂度为O(M*N),N为修改或求和需要扫描的区间大小。而对于树状数组,时间复杂度则为O(M*lgN)。加了一个lg,学过数学的我们应该都知道差距有多大。
在讲实现之前,我们需要先理解一个函数lowbit(x),这是一个自定义的函数,函数名是约定成俗的,作用就是返回x的二进制表示中最后一位1的权值
代码实现
- 1
- 2
- 3
- 4
- 5
写个长注释,假设x=10
10的二进制:1010,我们知道,一个数前加符号,就是用这个数的二进制取反加一。
-10的二进制:0101+1=0110
然后位运算符&(按位与),1010&0110=10,十进制表示就是2
所以lowbit(10)=2
这个函数很重要,所以先在这里交代清楚原理。
下面上图,讲讲实现树状数组(图来自百度百科)
图中有两个数组,数据都接收到底层数组a中,而数组c则是树状数组(看形状是不是很像个树)。 从图中可以直观的看到
c[1]=a[1];
c[2]=a[1]+a[2];
c[3]=a[3];
c[4]=a[1]+a[2]+a[3]+a[4];
c[5]=a[5];
c[6]=a[5]+a[6];
c[7]=a[7];
c[8]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7]+a[8];
假设结点为n,那么结点n所管辖的区间为2的lowbit(n)次方
即:c[n]=a[n-(2^lowbit(n))+1]+…..+a[n];
这样通过lowbit函数,把底层数组a和树状数组c联系了起来。
求数组a的前n位和
代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
假设n=8,lowbit(8)=8,while循环只持续了一次,得到的结果c[8]也与实际吻合
(发现没有,求前8位和,实际上只循环运算了1次!)
假设n=6,lowbit(6)=2,获取c[6]=a[5]+a[6]后,n=4;lowbit(4)=4;获取c[4]=a[1]+a[2]+a[3]+a[4];最终获取的就是a[1]+..+a[6];
(求前6位和,实际只循环运算了2次!)
还理解不了?那简单,把代码背下来,记住这个函数的返回值就是前n位和。
下面是修改,将数组a的第k位增加(或减少)num
代码
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- 树状数组
- Js中Prototype、__proto__、Constructor、Object、Function关系介绍
- 如何用studio将一个Android工程转成一个jar文件
- OpenGl 4.x for Mac开发环境配置
- 解决IOS项目中部分页面竖屏,部分页面横屏的问题
- Exception in thread "main" org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token:
- 树状数组
- 英语单词
- BZOJ 1305 [CQOI2009]dance跳舞
- python入门:正则表达式(regular)
- C++协程(1):协程原理及实现方式概述
- html表格的例子
- 用Category方式给UITapGestureRecognizer添加Tag属性
- 线段_线段树
- calcHist函数