树状数组
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树状数组相关的知识,希望对你有一定的参考价值。
奇妙的数据结构。
常用于 单点修改、区间查询。也可以通过某些手段进行 区间修改、单点查询。
本篇主要讨论后者。
——————————————————————————————————————————————————————————————————————
讨论之前,先上一下单点修改、区间查询的代码:
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).
以上是关于树状数组的主要内容,如果未能解决你的问题,请参考以下文章