讲树状数组之前,首先要来夸夸树状数组。
树状数组真的是一种好东西啊~~~代码极短,又非常好写,很实用,好东西呐。
夸完了树状数组,现在就来讲讲树状数组。
树状数组(Binary Indexed Tree),又名二叉索引树,Fenwick树,其处理的问题模型一般可以转化为如下形式:
定义一个数组
a[1..n]
a
[
1
.
.
n
]
,并维护一下两个操作:
- 修改,给 a[i] a [ i ] 加上某个增量 delta d e l t a 。
- 查询,询问某个前缀 a[1..index] a [ 1.. i n d e x ] 的和,即 ∑indexi=1a[i] ∑ i = 1 i n d e x a [ i ] 。
显然,朴素的算法能够在 O(1) O ( 1 ) 的时间内处理修改操作,但对于查询操作需要 O(n) O ( n ) 的时间复杂度,这在查询次数较多的情况下是接受不了的。而树状数组可以达到在 O(logn) O ( log n ) 的时间内完成修改和查询操作。
我们知道,每个整数可以表示为若干个2的幂次之和。相似的,对于每次求前缀和,我们也希望能够将其分解为一系列恰当的,不相交的”子集”,进而求出它们的和。
举例来讲, 7=4+2+1=22+21+20 7 = 4 + 2 + 1 = 2 2 + 2 1 + 2 0 那么求前缀和 ∑7i=1a[i] ∑ i = 1 7 a [ i ] ,我们也希望能够将它分为 3 3 个子集的和。一般地,如果前缀下标 的二进制中有 m m 个 , 我们就希望将其分解为 m m 个子集之和。基于这种思想,我们构造如下的表格: