「学习笔记」树状数组

目的:用数组来模拟树形结构。

树状数组可以解决大部分基于区间上的更新以及求和问题。


图中红色部分为 $C$ 数组,代表树状数组;黑色即为原来的数组 $A$。

可以得出:

$C[1] = A[1];$

$C[2] = A[1] + A[2];$

$C[3] = A[3];$

$C[4] = A[1] + A[2] + A[3] + A[4];$

$C[5] = A[5];$

$C[6] = A[5] + A[6];$

$C[7] = A[7];$

$C[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8];$

可以得出规律(其中 $k$ 为 $i$ 的二进制中从最低位到高位连续 $0$ 的长度):

$C[i] = A[i - 2 ^ k + 1] + A[i - 2 ^ k + 2] + ... + A[i];$

$Eg$:

当 $i$ 为 $4$ 时,$4$ 的二进制为 $100$,所以 $k$ 的值为 $2$。

代入。$C[4] = A[4 - 2 ^ 2 + 1] + A[4 - 2 ^ k + 2] ... A[4]$。

整理。$c[4] = A[1] + A[2] + A[3] + A[4]$。

其它数同理。


还有 $lowbit$ 的含义是取出 $x$ 的最低位 $1$,换言之,$lowbit(x) = 2 ^ k$。

代码即为 x & -x.

即可把刚刚找的规律变成:$C[i] = A[i - lowbit(i) + 1] + A[i - lowbit(i) + 2] + ... A[i];$。


代码:

// 求 A[1 到 x] 的和
int Query(int x) {
	int ans = 0;
	for (; x; x -= x & -x) ans += c[x];
	return ans;
}

// 在 i 的位置上加上 k
void Modify(int x, int val) {
	// 跳父亲
	for (; x <= n; x += x & -x) c[x] += val;
}
posted @ 2025-04-05 15:24  Aelt  阅读(4)  评论(0)    收藏  举报