树状数组专题
本文将以单点更新、区间求和开启树状数组的新世界。
—————————————————持续更新~———————————————————
同样是数组模拟树形结构,树状数组常和线段树比较优劣,放心,下面保证一字不提线段树,文末会有链接传送,专门比较树状数组和线段树。
还是先感谢优秀博客(写的十分详细了,这里只作总结):
树状数组详解
树状数组实现单点更新、区间求和
算法思想
- 数组A[]记录原数据, C[]表示我们的树状数组(数组长度和 A[]相同),数组的首位都遗弃
因为C[]的构建和二进制密切相关,下面的数均用二进制表示 - 构建过程:
- C[1] = A[1];
- C[10] = A[1] + A[10];
- C[11] = A[11];
- C[100] = A[1] + A[10] + A[11] + A[100];
- C[101] = A[101];
- C[110] = A[101] + A[110];
- C[111] = A[111];
- C[1000] = A[1] + A[10] + A[11] + A[100] + A[101] + A[110] + A[111] + A[1000];
好了用二进制确实麻烦,后面还是回归十进制表示。这其实是有规律的,直接ctrl+v优秀博客里的了
- $C[i] = A[i - 2^k+1] + A[i - 2^k+2] + … + A[i];$ //k为i的二进制中从最低位到高位连续零的长度
- 如对于C[6],二进制110低位开始有一个连续零,k取1,C[6]=A[5]+A[6]
- 我们先把k的问题放一边,假设C[]已经构建好了,前i项的和 Sum[i]这样得到:
$$Sum[i] = C[i] + C[i-2^{k1}] + C[(i - 2^{k1}) - 2^{k2}] + …$$
同样如Sum[6],二进制110的k取1, 二进制100的k取3,Sum[6] = C[6]+ C[4]; - 如何对C[i]求对应的k是关键,k的引入让人不仅赞美位运算的优雅。
- lowbit(int i)计算C[i]对应的$2^k$(于是lowbit取i的二进制中从低位到高位首次出现1的位置)
- 先给出最优答案
i&(-i)
- 仍然举C[6]的例子,二进制110对应的$2^k$为010,其实可以根据要求推出来;
只需保留低位到高位首次出现的1即可:i&(~(i-1))
因为-i就是i-1再取反(负数的补码知识,设想一下全为1时的二进制数表示-1),所以得到最优答案i&(-i)
搞定了lowbit()离成功就不远了~(费这么大劲求个区间和时间复杂度必须O(log n))
***注:更新A[i]时根据公式更新C[],计算 Sum[i]时也要利用lowbit()
———————————————————核心代码———————————————————
1 |
|
代码很短,实现了单点更新,区间查询[x,y]直接Sum(y)-Sum(x-1)
即可。
树状数组区间更新、区间求和
- 上面的update()只是针对单点更新,如果要对某个区间的值更新(如全加上某个值、减去某个值),需要引入差分的思想,D[]不断做差分 D[i] = A[i] - A[i-1];
直接借用人家优秀博客的例子吧:
A[] = 1 2 3 5 6 9
D[] = 1 1 1 2 1 3
如果我们把[2,5]区间内值加上1,则变成了
A[] = 1 3 4 6 7 9
D[] = 1 2 1 2 1 2
仅改变D[2]和D[6]的位置即可
于是之前写的代码都还有用,只是用D[]替换了 A[],在开始输入 A[]更新时的
update(i, a[i])
改为update(i, a[i]-a[i-1])
, 对于要更新的区间[x,y]增加update(x, temp); update(y+1, -temp);
显然此时Sum(i)求的是更新后单个A[i]的值了,但已经O(log n)实现了区间更新、单值查询了
要区间求和还需继续利用差分,后面就是纯公式推导了
$Sum(n) = A[1] + A[2] + … + A[n]
= (D[1]) + (D[1]+D[2]) + … + (D[1]+D[2]+…+D[n])
= nD[1] + (n-1)D[2] + … + 1D[n]
= n(D[1]+D[2]+…+D[n]) - (0D[1]+1D[2]+…+(n-1)D[n])
= n\sum_{i=1}^{n}{D[i]} - \sum_{i=1}^{n}{D[i](i-1)}$
于是又用两个数组sum1[] sum2[]替代了 D[]
—————————————————完整代码—————————————————————
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!