...
原数组是a1~a8,数组状数组是c1~c8,它们拥有的元素个数完全一样,并且都从下标1开始存储元素。
分析树数组和原数组的关系,列出对应的二进制:
树状数组节点下标 | 节点下标的二进制 | 对应原数组节点范围 | 最后一个元素下标 | 元素个数 |
---|---|---|---|---|
1 | 0001 | 1 | 1 | 1 |
2 | 0010 | 1~2 | 2 | 2 |
3 | 0011 | 3 | 3 | 1 |
4 | 0100 | 1~4 | 4 | 4 |
5 | 0101 | 5 | 5 | 1 |
6 | 0110 | 5~6 | 6 | 2 |
7 | 0111 | 7 | 7 | 1 |
8 | 1000 | 1~8 | 8 | 8 |
这里首先可以推导出这里首先介绍如何推导出cx
管理的元素个数,推导公式如下:
代码块 |
---|
int lowbit(int x) { return x & -x; } |
...
代码块 |
---|
void update(int k, int val) {
for(int i = k; i <= n; i += lowbit(i); { // 推导a[k]归哪些c[i]管理
c[i] += val;
}
} |
代入上面的表格进行验证即可。
...
代码块 |
---|
int getsum(int x) { int ans = 0; while(x >= 1) { ans += c[x]; x -= lowbit(x); } return ans; } |
同样代入上面的表格进行验证即可。
最后是如何建立树状数组,示例代码如下,这时在每确定一个c[i]
时,都会更新一次c[i]
的直接父结点,则于父结点的值只来自于子结点求和,所以建树的时间复杂度为O(n):
代码块 |
---|
#define MAXN 1005
int a[MAXN];
int c[MAXN];
int n;
void init() {
for(int i = 1; i <= n; i++) {
c[i] += a[i];
int j = i + lowbit(i);
if(j <= n) t[j] += t[i];
}
} |