概要
树状数组
是指一个数组C里存储着另一组数A一部分的和
C[i]=A[i]+A[i-1]+….+A[i-2^k+1]
k指i二进制形式,末位1的位数(最后一位的位数从0开始)
ex: i = 6 = 0110, k = 1, C[ i ] = A[ 6 ] + A[ 5 ]
RT:
我的理解它是按照二进制最低位1的位置来分层
如:
i = xxx1(奇数) 则只保存当前index的值(height = 1 )(叶子结点)
i = xx10 (2的奇数倍) 保存(包括自己的)往前两个数的和 ( height = 2 )
i = x100(2^2 的奇数倍) 保存往前四个数的和 ( height = 3 )
以此类推,来达到最快求和
计算
提取出最末位的1
方法:lowbit = k & (-k) (-k = ~k + 1 )
各位之间的关系
要想添加或计算一段数的和,就需要知道该节点与底层节点哪些节点有关系
方法:k = k + lowbit ( k )
ex:如图可以发现C[1],C[2], C[4], C[8]之间存在联系
如果改变了C[1]的值,则C[2], C[4], C[8]也要跟着修改
这种关系是怎么传递的?
依旧和lowbit有关
1 = 0001, lowbit(1) = 0001 = 1
1 + 1 = 2 就传递到了高度为2的位置
同理
2 = 0010, lowbit(2) = 0010 = 2
2 + 2 = 4 传递到h = 3
换一个C[6]
i = 6 = 0110, lowbit(6) = 0010 = 2
6 + 2 = 8 传递到h = 4
代码
#include <cstdio>
#include <iostream>
#define n 10
using namespace std;
int C[ n + 1 ];
int lowbit ( int k ) { return k & ( -k ); } //取最低位的1
void write ( int k, int a ) { //保存新的数进入数组
while ( k <= n ) { //当k不超过数组的最大值,则不断从下到向上修改相关联的数据
C[ k ] += a; //修改关联值
k += lowbit ( k ); //计算下一个k的位置
}
}
int getsum ( int k ) { //从上到下求和
int sum = 0;
while ( k ) {
sum += C[ k ];
k -= lowbit ( k );
}
return sum;
}
int main () {
for ( int i = 1; i <= n; i++ ) {
int a;
cin >> a;
write ( i, a );
printf ( "Num:%d %d ", i, C[ i ] );
printf ( "Sum:%d %d\n", i, getsum ( i ) );
}
return 0;
}
运行结果
1 2 3 4 5 6 7 8 9 10
Num:1 1 Sum:1 1
Num:2 3 Sum:2 3
Num:3 3 Sum:3 6
Num:4 10 Sum:4 10
Num:5 5 Sum:5 15
Num:6 11 Sum:6 21
Num:7 7 Sum:7 28
Num:8 36 Sum:8 36
Num:9 9 Sum:9 45
Num:10 19 Sum:10 55