版本比较

标识

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

...

原数组是a1~a8,数组状数组是c1~c8,它们拥有的元素个数完全一样,并且都从下标1开始存储元素。

分析树数组和原数组的关系,列出对应的二进制:

树状数组节点下标节点下标的二进制对应原数组节点范围最后一个元素下标元素个数
10001111
200101~222
30011331
401001~444
50101551
601105~662
70111771
810001~888

这里首先可以推导出这里首先介绍如何推导出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];
	}
}