前言
树状数组,即树形存储的数组,又称Binary Indexed Tree或Fenwick Tree。
抛开它树形的存储结构,这种神奇的数据结构的应用看起来与「 树」没什么关系:
有一个序列 A = ( A 1 , A 2 , … , A N ) A=(A_1,A_2,\dots,A_N) A=(A1,A2,…,AN),在不超过 O ( log N ) \mathcal O(\log N) O(logN)的时间复杂度内完成下列操作:
→ \to~ → 求 [ L , R ] [L,R] [L,R]区间内所有数之和。
→ \to~ → 指定一个元素 A x A_x Ax,将其加上 k k k。
如果想要使求和操作尽可能快,很容易想到前缀和,这样求和操作只要 O ( 1 ) \mathcal O(1) O(1)的时间,但更新操作的时间复杂度就升至 O ( N ) \mathcal O(N) O(N),无法满足题目要求;反之,若直接暴力维护 A A A中所有元素的值,则虽然更新操作只需要 O ( 1 ) \mathcal O(1) O(1),但求和操作的时间又变成了 O ( N ) \mathcal O(N) O(N),还是满足不了要求。那有没有一种算法,综合了两种方式的优势,达到题目时间要求呢?
肯定有,那就是今天说的——树状数组。
基本算法
洛谷 P3374【模板】树状数组 1
同“前言”中的部分, 1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1≤n,m≤105,其中 m m m为操作总次数。
由于 n , m ≤ 1 0 5 n,m\le 10^5 n,m≤105,所以 O ( n m ) \mathcal O(nm) O(nm)的暴力解法肯定行不通,需要使用 O ( M log N ) \mathcal O(M\log N) O(MlogN)的树状数组。其存储结构大致上是这样的:

是不是已经有些明白了?这里我们我们把 B B B当作树状数组的内部存储,则据图可知:
- B 1 = A 1 B_1=A_1 B1=A1
- B 2 = A 1 + A 2 B_2=A_1+A_2 B2=A1+A2
- B 3 = A 3 B_3=A_3 B3=A3
- B 4 = A 1 + A 2 + A 3 + A 4 B_4=A_1+A_2+A_3+A_4 B4=A1+A2+A3+A4
- B 5 = A 5 B_5=A_5 B5=A5
- B 6 = A 5 + A 6 B_6=A_5+A_6 B6=A5+A6
- B 7 = A 7 B_7=A_7 B7=A7
- B 8 = A 1 + A 2 + A 3 + A 4 + A 5 + A 6 + A 7 + A 8 B_8=A_1+A_2+A_3+A_4+A_5+A_6+A_7+A_8 B8=A1+

本文介绍了树状数组(Binary Indexed Tree),一种在O(log N)时间内支持区间求和与元素更新的数据结构。通过离散化和树状数组原理,实现高效逆序对计算及区间更新技巧。对比线段树,树状数组在实现和速度上有明显优势。
最低0.47元/天 解锁文章
790

被折叠的 条评论
为什么被折叠?



