树状数组 重温

upd.on 2025.7.5 修复一些表述错误

 

详解


对于单点修改,前缀查询一类问题。我们如何 logn 的时间维护?

 

无非就是拆区间。可以区间折半,乃线段树。

也可以拆位,考虑把区间拆成多个二进制下的区间,也能做到 logn 的时间,这就是树状数组。

 

比如 21 的前缀和,拆成 10101。也就是

$s[0, 21]=s[21-2^{0}, 21] + s[21-2^0-2^2, 21-2^0] + s[21-2^0-2^2-2^4, 21-2^0-2^2]$

$s[0, 21]=s[20, 21] + s[16, 20] + s[0, 16]$

 

这里拆 s 的过程其实是每次都去掉末尾二进制的 1,我们可以用 lowbit 获取末尾二进制的 1,实现不断拆 s。

lowbit:为了取到末尾1,需要每一位取反后加 1 ,这样低位全为 0,高位和原数全部不一样。此时再和原数 与 一下即可。相当于与上原数的负数。

(特别注意一点,lowbit(0)=0,代码实现时要注意死循环问题)

 

由此,我们引入 $tr$ 数组记录二进制下的各个区间信息。

也就是:tr[u] 管理 [u-lowbit(u), u] 的区间和。

这样相当于把 s 拆成若干个 tr,组成若干条链,最终构成了树形结构图。

 

一个性质:u 的父亲是 u+lowbit(u),是容易推的。

 

单点修改:根据上述性质,修改 u 只会对其父亲有影响,不断改父亲即可。也就是不断加上 lowbit(u)

前缀查询:就是拆 s 的过程,不断拆即可,也就是不断减去 lowbit(s)。

 

板子


[一维] 单点加 区间查


很板,把区间用前缀表示即可。记录详情 - 洛谷 | 计算机科学教育新生态

树状数组的本质就是单点加,前缀查!

 

[一维] 区间加 单点查


记录详情 - 洛谷 | 计算机科学教育新生态

区间加,结合树状数组刚好是维护前缀和,所以可以转换成差分实现。那单点查就是查前缀和,直接查就好。

 

[一维] 区间加 区间查


记录详情 - 洛谷 | 计算机科学教育新生态

区间加维护差分即可,区间查呢?推下式子。

 

区间查询:令 $sum(1, R)$ 表示 $\sum_{i=1}^R a_i$

由差分,$sum(x, x)=\sum_{i=1}^x tr_i$

先考虑一段的情况,即
$sum(1, R)=\sum_{i=1}^R \sum_{j=1}^i tr_j$

再展开上式得 $\sum_{i=1}^Rtr_i \times (R-i+1)$(可以画图理,即序列当前数 i 只会被 i 后面的数加到)

上式的求和里跟 $R$ 有关比较难算,美化下,让求和里尽量只和 $i$ 有关,得 $R \times \sum_{i=1}^Rtr_i - \sum_{i=1}^Rtr_i \times (i-1)$

好看多了,让 $tr2_R$ 维护 $\sum_{i=1}^Rtr_i \times (i-1)$ 就做完了。

 

[二维] 单点加 区间查


提交记录 #2332013 - LibreOJ

就是多了一维嘛,tr[m][n],相当于 m 组一维的 tr[n]。但是对于新一维 m 也可以同样处理方法,加减 lowbit 快速管理。

区间查就类似二位前缀和即可。

 

[二维] 区间加 单点查


提交记录 #2332015 - LibreOJ

同样维护二维差分即可。

 

[二维] 区间加 区间查


记录详情 - 洛谷 | 计算机科学教育新生态

令 $sum(a, b, c, d)$ 表示 $(a, b)$ 到 $(c, d)$ 的和。

$sum(1, 1, a, b)=\sum_{i=1}^a \sum_{j=1}^b \sum_{k=1}^i \sum_{u=1}^j tr_{k ,u}$

展开,$\sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times (a-i+1) \times (b-j+1)$(可以画图理,即矩阵当前数 [i, j] 只会被 [i, j] 到 [a, b] 矩阵里的数加到)

再展开,$\sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times (ab-aj+a-bi+ij-i+b-j+1)$


优美下,尽可能让 $tr_{i, j}$ 与 $i$,$j$ 有关,把 $a$,$b$ 提到求和前面处理,即按 $i$ 和 $j$ 提式子:

$\sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times (ij-i(b+1)-j(a+1)+(ab+a+b+1))$

所以分开维护四个式子即可:

1. $\sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times i \times j$

2. $(b+1) \times \sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times i$

3. $(a+1) \times \sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} \times j$

4. $(ab+a+b+1) \times \sum_{i=1}^a \sum_{j=1}^b tr_{i ,j} $

 

 

 

例题


[简化+容斥思想] Loj10115


提交记录 #2330628 - LibreOJ

1.简化问题:因为区间内元素互不相同,我们只需要关心区间端点,从而对左右端点分别建树状数组。

2.容斥。直接求难,用全部方案-不合法。且这里的全部方案比较巧妙。

 

[dfs 序] CF383C


 

Submission #327664514 - Codeforces

1.跟子树操作有关,一定要想到 dfs 序,且注意把树拍成序列后,树上的点编号和序列下标要对应好。

2.val, -val, -(-val),得想到奇偶相关,这样就能分离奇偶,方便处理。

 

posted @ 2025-05-24 12:42  cn是大帅哥886  阅读(5)  评论(0)    收藏  举报