树状数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组相关的知识,希望对你有一定的参考价值。

转载自EdwardFrog‘s Home

 

奇妙的数据结构。

  常用于 单点修改、区间查询。也可以通过某些手段进行 区间修改、单点查询

  本篇主要讨论后者。

——————————————————————————————————————————————————————————————————————

讨论之前,先上一下单点修改、区间查询的代码:

 struct Node {
	int tree[MAXN];
	void add(int x, int v) {
		while (x <= n) {
			tree[x] += v;
			x += x&(-x);
		}
	}
	int sum(int k) {
		int ans = 0;
		while (k) {
			ans += tree[k];
			k -= k & (-k);
		}
		return ans;
	}
} T;

————准备材料———————————————————————————————————————————————————————————

  原数组a,和它的差分数组 C 。

————制作过程———————————————————————————————————————————————————————————

区间修改

  树状数组的修改并没有真正修改原数组的数,只是利用各种玄学得到修改后的那个结果 。

  a[ n ] = c[ 1 ] + c[ 2 ] + ... + c[ n ]     (不懂的话,自己举个例子试试)

  对a中的某一段连续的区间[l,r]进行修改时,c数组中只有c[l]和c[r + 1]改变。
  也就是说,要进行对[l, r]的修改,实际上改变c[l],c[r + 1]两个值即可。  

区间修改[l,r]+=v:

add(c[l],v),add(c[r+1],-v);        add(c2[l],(l-1)v),add(c2[r+1],-rv);

 

区间查询

  考虑普通做法中,维护一个前缀和数组sum。求[l, r]一段的区间和只要求 sum[r] - sum[l - 1] 即可,推一推可以知道

 

1 sum[n] = a[1] + a[2] + ... + a[n]
2     = c[1] + (c[1] + c[2]) + ... + (c[1] + c[2] + ... + c[n])
3     = n * (c[1] + ... + c[n]) - (0 * c[1] + 1 * c[2] + ... + (n - 1)*c[n])

  现在问题就变成了求 (c[1] + ... + c[n]) 和 (0 * c[1] + 1 * c[2] + ... + (n - 1)*c[n]) 。

  再开一个数组 c2,c2[ i ] = c[ i ] *(i - 1)。

 

求前缀和sum(1,n):

sum(1,n)=n*query_c(n)-query_c2(n).

求区间和sum(l,r):

sum(l,r)=sum(r)-sum(l-1).

以上是关于树状数组的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之树状数组从零认识树状数组

树状数组和线段树有啥区别?

树状数组

树状数组

树状数组

如何利用树状数组修改一个区间?