1.作用:
树状数组是一种基于树形数据结构,擅长于进行区间查询 , 区间修改,等一系列区间操作的数据结构 , 因其足够优秀的复杂度(log级别)和并不是很复杂的代码量(较于线段树)而广受好评图示
2.基本操作
1.lowbit
上图中 , 黑色的是原数组 , 红色的则是我们的树状数组 , 我们可以发现 , 对于每一个树状数组中的元素c[i] , 它的值应该是a[i - k + 1] + a[i - k + 2] + ...... + a[i] ,(k 为 i 转为二进制时由右到左第一个为1连带着它右边的一系列0又转为十进制的值) , 比如14 , 他转化为二进制应该是1110 , 那么k二进制值应该就是10 , 也就是2 , 所以c[14] = a[13] + a[14] , 对于k值的求法 , 很是巧妙 , 用到了二进制中负数的补码特性 , 本蒟蒻法力有限 , 在此只给出代码 ,
int lowbit(int x){
return x & (-x);
}
2.初始化BIT
k值有了着落 , 我们的树状数组(BIT)的初始化也就有了法 , (本蒟蒻在此用了前缀和 , 也可以直接暴力for循环累加也行 , 不影响BIT的初始化)
void MakeBIT(){// a 初始数组 , sum 前缀和数组 , BIT 维护a的树状数组
for(int i = 1 ; i <= n ; i++){
sum[i] = sum[i - 1] + a[i];
}
for(int i = 1 ; i <= n ; i++){
BIT[i] = sum[i] - sum[i - lowbit(i)];
}
}
3.前缀和
有了初始化 , 我们就要进一步看看 BIT 有何神妙了
我们不妨换个思路想 , BIT数组是由一段连续的子区间和的集合 , 那我们是否可以求到前x项的和呢 ?
答案是肯定的 , 下面给出代码