acwing 树状数组模板

99 阅读3分钟

树状数组的作用:

一.快速的求给某区间内的某个数加上某一个数

二.在O(longn)下快速的求出前缀和。

关于二.前缀和可以用O(1)时间打表求出前缀和,为什么还要用树状数组呢?

因为前缀和只能查询,但是不能修改,而树状数组可以修改。

比如想把某段区间内的x修改为v:

image.png 那我们可以把x+(-X)+v=v。

假设V比X大的话,那C[y]([v,y]段前缀和) 的值也会因此变大,同理,C[z]的值也会受到影响,最坏的情况是后面所有的数都受到了影响,那么时间复杂度就为O(n)了,如果用树状数组,时间复杂度就为O(longn):

image.png x值变了,整个前缀和的值也都变了。

树状数组画图

a[]代表原数组,C[]代表树状数组。

树状数组用来维护一个一维数组的信息,记住下标要从1开始

image.png

第0层存的都是原数组奇数位置上的值:

image.png

此时C[1]=a[1]

第1层存的是刚好可以被2^1整除的树:

image.png

C2=C[1]+a[2]
C6=C[5]+a[6]
C10=C9+a[10]
C14=C13+a[14]

第二层存的是刚好可以被2^2整除的树:

image.png

C4=C2+C3+a4

第2层存的是可以被2^3h整除的树:

image.png

C8=C4+C6+C7+a8

第3层存的是可以被2^4整除的数:

image.png

C16=C8+C12+C14+a16

根据最后一张图,我们总结这样一个规律:

C2是a1~a2的和

C4是a1~a4的和

C8是a1~a8的和

……

C16是a1~a16的和

Cn是前n段的和

树状数组求前缀和公式

怎么确定C[x]在第几层的?

其实是根据X的二进制有几个0判断它在第几层:

比如C[4],4的二进制是:0100,所以在第二层:

再比如C[8],二进制为:01000,所以在第三层:

image.png

C[X]求前缀和的公式为:

C[x]=(x-2^k,x](注意左开右闭)

2^k就是x的末尾有k个0的意思。

比图C[4]=a1+a2+a3+a4,我们套公式验证一下:(4-2^2,4]=(0,4](注意左开,不包含0,从a1开始)。

有一个函数叫lowbit(),这个函数的功能是你给它传x值,如果x二进制末尾有0,它就会返回2^k,否则返回-1.

因此树状数组求前缀和公式可以表示为: C[x]=(x-lowbit(x),x];

现在我们求出x段的前缀和了,那么我们要求整段的前缀和:

模板题

image.png

我们可以for循环遍历i,i为每个节点的下标,不断累加lowbit(i)就可以求出整段的前缀和了。

1264. 动态求连续区间和 - AcWing题库

这道题让我们修改区间内某元素,求前缀和,可以用树状数组求: image.png

AcWing 1264.代码托管