数据结构-树状数组
前置知识
- 前缀和
- 位运算和负数的补码存储
思路
我们需要维护一个支持单点修改,区间求和的数据结构,并且要求在线,一般使用树状数组解决。
树状数组是一个树形的数据结构。
定义数
x
(
x
∈
N
+
)
x(x\in \N^+)
x(x∈N+) 的
l
o
w
b
i
t
(
x
)
lowbit(x)
lowbit(x) 为
x
x
x 在二进制表示下最低的非零位所表示的数,易发现可表示为
x
⊕
(
−
x
)
x\oplus(-x)
x⊕(−x)。
令元素
a
x
a_x
ax 对应的节点
x
x
x 满足
s
x
=
∑
i
∈
(
x
−
l
o
w
b
i
t
(
x
)
,
x
]
a
i
s_x=\sum_{i\in(x-lowbit(x),x]}a_i
sx=i∈(x−lowbit(x),x]∑ai
即
s
x
s_x
sx 表示
(
x
−
l
o
w
b
i
t
(
x
)
,
x
]
(x-lowbit(x),x]
(x−lowbit(x),x] 的区间和。
容易发现,节点
x
x
x 的父节点为
x
+
l
o
w
b
i
t
(
x
)
x+lowbit(x)
x+lowbit(x)。
树状数组长这样:
节点上的权值表示其
l
o
w
b
i
t
lowbit
lowbit 值。
此时考虑数据结构的操作。
- 单点修改
不断向上爬树,对祖先结点修改。 - 区间求和
每次令 x − l o w b i t ( x ) → x x-lowbit(x)\to x x−lowbit(x)→x,不断累加,容易发现覆盖了区间 [ 1 , x ] [1,x] [1,x],此时采用前缀和的思想。
数据结构参数
- 时间复杂度: O ( n log n ) O(n\log n) O(nlogn)
- 空间复杂度: O ( n ) O(n) O(n)
实现代码
int s[MAXN];
int lowbit(int x){return x&-x;}
void update(int x,int k){
while (x<=n){
s[x]+=k;
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while (x){
res+=s[x];
x-=lowbit(x);
}
return res;
}