树状数组
1.来源
树状数组(二叉索引树)主要是为了解决动态连续和的查询问题,简而言之,就是一个一个数组的某些值在不断地更新,而这时候我们要查询某一区间的和的时候就会非常的麻烦,于是呢,树状数组应运而生。
树状数组主要有两个操作:数组元素的更新与某个区间内的查询
对普通数组进行一次修改或特定区间求和,时间复杂度为 O(N),N 为修改或求和需要扫描的数组区间大小。但树状数组则可以很好的解决这个问题,时间复杂度则为 O(logN)。加了一个log,学过数学的我们应该都知道效率优化有多大。
2.概念相关
首先需要介绍树状数组的构造,如它的名字一样,画出的树状数组就像一棵树,它把每一个下标按照二进制最后一个1的不同位置分为不同的等级,如下图:
每一个元素都是前面等级比它低的元素值之和(当然包括自己了),相应的,每一个元素的值都是它后面高等级元素的值的一部分。例如2,前面等级低的只有1,所以Tree[2]=Tree[1]+value[2],4就是1,2,3,4值的和:Tree[4]=Tree[2]+Tree[3]+value[4]以此类推......
那么问题来了:我们如何取得他们的等级呢?这里就要用到一个函数:lowbit()(非标准库函数),大概长这样:
int lowbit( int x ){
return x & -x;
}
这个函数的功能就是返回最后一个1的位置——对,没错!就是那个等级。。。。于是更新元素的方法就可以推出来了↓↓↓
//元素值更新,初始化为0
void add ( int pos , int value ){
while( pos<=n ){
Tree[pos] += value;
//当前元素的位置加上当前元素的等级就是下一个等级比它高的元素的位置,是不是很神奇???
pos += lowbit(pos);
}
}
然后呢,就是查询操作了,看看上面的图,你是不是已经发现什么了?如果我们要求sum[7],从图上可以发现:我们只要将4,6,7的值加起来就行了!也就是sum[7]=Tree[4]+Tree[6]+Tree[7]。从数组值更新中得到启发:当前元素的位置加上当前元素的等级就是下一个等级比当前元素高的元素的位置,那么当前元素的位置减去当前元素的等级就是。。。。
//取得1~end的元素值之和
ing find( int end ){
int sum = 0;
//Tree[0]是不使用的
while( end>0 ){
sum += Tree[end];
//取得前一个等级比当前元素高的元素的位置
end -= lowbit(end);
}
return sum;
}
好吧,讲完了,你们懂了吗٩(๑❛ᴗ❛๑)۶