是什么
使用数组来模拟树形结构
可以解决什么问题
大部分基于区间上的更新和求和问题
优点和缺点
修改和查询的复杂度为O(logN),比线段树系数少得多,比传统数组要快,而且容易编写。
我们使用A数组表示原来的数组,C数组表示我们的树状数组
可以表示为
C[i] = A[i-2k+1] + A[i-2k+2]+…+A[i];
k为i的二进制中从最低位到高位连续零的长度
C[1] = A[1] 1 = 1 k=0
C[2] = A[1] + A[2] 2 = 10 k=1
C[3] = A[3] 3 = 11 k =0
C[4] = A[1]+A[2]+A[3]+A[4] 4 = 100 k=2
…
当我们要求前n项的和时,SUM(n) = C(i) + C(i-lowbits(i)) + C(i-lowbits(i) - lowbits(i-lowbits(i))) +…
4 = 100 -4 = 100 4&-4 = 100 -> 4
6 = 110 -6 = 010 6&-6 = 010 -> 2
7 = 111 -7= 001 7&-7= 1 ->1
8 =1000 -8 =1000 8&-8 = 1000 -> 8
10 = 1010 -10 = 0110 10&-10 = 10 ->2
所以 SUM(7)= C(7) + C(6) + C(4) + C(0)
lowbits就是求一个数的二进制&它负数的二进制时,最低非0的位置, x&(-x)
直接给出结论
- x是0时,结果为0
- x是奇数时,结果是1
- x是偶数时,结果是x中2的最大次方因子
更多的细节可以参考这篇博客 树状数组详解 - Xenny - 博客园 (cnblogs.com)
下面给出一个树状数组
int n;
int a[1005],c[1005]; //对应原数组和树状数组
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求A[1 - i]的和
int res = 0;
while(i > 0){
res += c[i];
i -= lowbit(i);
}
return res;
}
cin>>n;
for(int i = 1; i <= n; i++){ //注意是从1开始!!
cin>>a[i];
updata(i,a[i]); //输入初值的时候,也相当于更新了值
}