数状数组模板
树状数组,又称二叉索引树。
一般解决动态连续和查询问题。
也就是说,
给定一个含有n个元素的数组A,要求你设计一个数据结构,支持2个操作:
1.Add(x, d),也就是让第x个元素Ax增加d
2.Query(L, R)也就是计算AL + AL+1 + ...+AR
我们知道,在数据量很大的情况下,朴素的算法时间复杂度其实是非常高的。
所以现在要面临的问题就是如何让上述的两个操作花费的时间更少。
这里需要引进一个名为二叉索引树的概念。
二叉索引树:

在这之前,我们看看一个名为lowbit的概念。
啥是lowbit呢?
首先谈谈补码的概念。
假设 x = 11 它的二进制则为 x :1011
它的反码为: x : 0100
补码为反码末尾加一: x : 0101
OK,现在说说lowbit,它就是x&-x
啥意思?
就是取x二进制位最右边的1所对应的值,比如11就是1(1011),38288(1001010110010000)就是16(10000)
也就是说 lowbit(x) = 2^k其中,k为x&-x中后缀0的长度
给出代码:
int lowbit(int x) { return x&(-x); }
下面看看这个图:

可以发现,对于结点i,如果它是其子树的左子节点,则其父节点的编号为:i+lowbit(i);
反之如果其为右子树结点是,其父结点编号为:i-lowbit(i);
所以,我们开一个辅助数组C
Ci = A[i-lowbit(i)+1] + A[i-lowbit(i)+2] + A[i-lowbit(i)+3] +...+ A[i]
可以发现
在BIT(二叉索引树)中,每个灰色的结点i都是以自身为结尾的水平长条(对于lowbit = 1的点输就是它自己)
说了这么多,直接看图

下面是演示:
首先是求sum(11)的图:
可以知道(设A数组其从1开始)
C[11] = A[11]
C[11 - lowbit(11)] = C[10] = A[9] + A[10]
C[10 - lowbiot[10]] = C[8] = A[1] + A[2] + ... + A[8]
C[8 - lowbit(8)] = C[0] = 0;
演示完毕。
给出代码:
int sum(int x) { int ans = 0; while(x > 0) { ans += c[i]; x -= lowbit(x); } return ans; }
这是单点更新操作的图示(假设更新点3):

下面解释一下:
单点更新A[3],也就是更新C[3] = A[3]+x
C[3 + lowbit(3)] = C[4]+x
C[4 + lowvbit(4)] = C[8]+x
C[8 + lowbit(8)] = C[16] = 0(由于16大于15)
演示结束,下面看代码
void add(int x, int d) { while(x <= n) { c[x] += d; x += lowbit(x); } }

浙公网安备 33010602011771号