树状数组是一个查询与修改复杂度都为log(n)的数据结构,假设数组a[1],a[2],......,a[n],那么查询a[1]+...+a[n]的时间是Log(n),而且是一个在线的数据结构,修改某一个元素的值也是一样的时间复杂度。
我们来看下面这个图:
令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
...
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
这里有一个有趣的性质:
设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,
所以很明显:Cn = A(n – 2^k + 1) + ... + An ;
树状数组有三个主要的操作:
(1)计算2^k的函数:
(2)求1 - id的和值:
(3)对某一位操作函数如下:
树状数组是一个很高效的进行区间统计的数据结构,在思想上类似于线段树的操作,一般来说,能用树状数组的题目也可以用线段树的方法去做!但是树状数组比线段树节省空间,编程复杂度比线段树低,但适用范围比线段树小。
树状数组的扩展:(推广到二维)
二维树状数组跟一维的树状数组其实都差不多:只是用了二维数组而已。
对于求2^k是一样的!
修改某一元素的代码如下:
求和的函数如下: