树状数组(小白)
树状数组(BIT)是一种利用树的2进制特征进行检索的树状结构。树状结构是一种奇妙的数据结构,不仅非常高效,而且代码十分简洁(比线段树的代码要短且更易理解,但是可以解决的问题也是有限的,没有线段树那么广泛)
这个大圆就相当于线段树能解决的问题,小圆就是树状数组能解决的问题,一般来说能用树状数组解决的就优先用树状数组
树状数组的概念
树状数组就是用来 动态的求前缀和·(代码的时间复杂度在log n之内)
一般来说就是两个操作 :1.单点修改 2.区间查询(通俗来说就是给某个位置上的数加上一个数;求前缀和)
当然平时做题的时候也不止这两种操作 比如有1.区间修改 2.单点查询 或者 1.区间修改 2.区间查询
(这几种操作本质上还是用树状数组解决 只不过是需要用到差分 将它转化为最初的两个操作)
下面开始举一个例子
长度为n的数列{a1,a2.....,an},进行以下操作。
(1) 修改元素add(k,x);把ak(ak为数列中第k个数)加上x;
(2)求和sum(x):x<=n,sum=a1+a2.....+ax;
那么区间和ai+.....+aj=sum(J)-sum(i-1).
这个程序很好写,用循环加或者前缀和,复杂度是O(n).但是,如果n很大的话,这样做的效率会非常低。所以我们需要掌握树状数组。
先看代码:
int lowbit(int x){
return x&-x;
}
void add(int x,int v){ //更新数组tree[]. ax=ax+d,修改跟ax有关的tree[]
for(int i=x;i <=n;i +=lowbit(i)) tree[i] +=v;
}
int sum(int x){ //求和:sum=a1+a2....+ax
int res=0;
for(int i=x;i >0;i -=lowbit(i)) res +=tree[i];
return res;
}
add()和sum()的复杂度都是O(log2 n).(打不出来这个东西 😂)
在理解上述代码的之前 先看我下面这张图
这张图就是解释了add()构建tree[]数组 tree[1]=a[1] tree[2] =a[1] +a[2]; tree[3] =a[3] tree[4] =a[1]+a[2]+a[3] … 连线就代表此时tree[x]的值为那些连线位置的和
可是为什么是这些值呢
这就要看这个神奇的操作了 lowbit(x) .lowbit(x)=x&-x,功能是找到x的二进制的最后一个1.其原理是利用负数的补码表示,补码是原码取反加一。例如x=6=00000110,-x=x补=11111010,
那么lowbit(x) =x&-x=10(2进制)=2;
仔细观察就会发现 让补码与原码一一对应 以x的2进制的最后一个1为中心 原码和补码左边的部分是刚好相反的 所以在对x&-x操作时 前面的部分都为0 0&0 当然也为0 所以x&-x=10(2进制的)=2;
是不是很妙
lowbit(x)有什么用呢?
在求和计算和tree[]数组的更新都可以通过lowbit()完成。
借助tree[]数组求sum,例如:
sum[8] =tree[8];
sum[7]=tree[7]+tree[6]+tree[4];
sum[9]=tree[9] +tree[8];
那如何得到上面的关系呢
对tree[]的查找可以通过lowbit(x)实现。例如sum[7]=tree[7]+tree[6]+tree[4];
首先从7开始,加上tree[7] ;
然后7 - lowbit(7)(值为1) =6 再加上tree[6] ;
然后6 - lowbit(6)(值为2) =4 再加上tree[4]
最后4 - lowbit(4) (值为4) =0,结束;
关于tree[ ]数组的更新
当你改变a[x]的值 加个3 tree[]数组的值也应当变化 这个也使用了lowbit(x)
例如 当你改变a[6]的值后
对于tree[]数组来说肯定是6以后的位置收到影响 所以
tree[6] +=3; 然后 6 +lowbit(6) =8;
tree[8] +=3; 然后8 +=lowbit(8) =16;
以此类推 直到tree[n];
所以add() 也是用的这种方法 来初始化tree[]数组
for(int i;i<=n ;i ++) add(i,a[i]);
这样就是对tree[]数组进行初始化
*这里需要注意一下树状数组的下标起始一定是从1开始 如果题目下标有0的话 可以进行加1处理
说了这么多 应该都懂了树状数组了吧
接下来就开始 实战演练了 帮助你巩固 加强理解
这是树状数组的一道模板题 直接套就可以了(https://www.luogu.com.cn/problem/P3374)
然后关于树状数组较难的题 我也还在学习中😂 以后遇到会加进去的
那就先这样吧 本人小白 如有错误欢迎各位大佬指正
//南昌理工学院ACM集训队