树状数组
MarsTraveller · · 算法·理论
树状数组
树状数组是一个查询和修改复杂度都为
O(\log n) 的数据结构。其主要用途为数组的单点修改与区间求和,效率远远优于线段树。
一、基本思想
树状数组是一种基于二进制唯一分解性质的一种数据结构,其基本用途是维护序列前缀和,对于一个区间
[1,x] ,树状数组将其分为\log x 个小区间,从而快速询问区间和。
下面举一个例子:若数
- 区间
[{\color{blue}1},{\color{red}2^4}] (长度{\color{red}2^4} )。 - 区间
[2^4+{\color{blue}1},2^4+{\color{red}2^2}] (长度{\color{red}2^2} )。 - 区间
[2^4+2^2+{\color{blue}1},2^4+2^2+{\color{red}2^0}] (长度{\color{red}2^0} )。
二、基本算法
0. 前置:
我们将一个数的二进制分解后最小的那一个幂称为
由上文标红可知,一个区间
所以,对于给定数组
如图(
观察例图,发现树状数组有如下神奇的性质:
-
-
- 树的深度为
O(\log n) 。
这些性质是树状数组的精髓!
1. 单点修改(A_i += k )
根据树状数组的特性,对
void update(big id,big k)
{
for(;id <= n;id += lowbit(id))
{
tree[id] += k;
}
}
2. 区间查询(\sum_{i = l}^{r} A_i )
如下令:
我们可以得出区间
如:
那么如何求出
根据性质1,我们通过从
时间复杂度
big sum(big id)
{
big ans = 0;
for(;id >= 1;id -= lowbit(id))
{
ans += tree[id];
}
return ans;
}
单点修改 区间查询模板
例题:
- P3374 【模板】树状数组 1。
- P1908 逆序对。
- The Battle of Chibi。
3. 区间修改:
设在
考虑差分。将 区间