首先看树状数组是用来求前缀和比较方便的一种数据结构
sum[i] = Sigma a[i] =Sum(bit[x])
而区间修改也不难实现
就是引入一个差分数组del
del[i]表示对i~n的修改
这样的话也就是最del[i]求前缀和 就能得到i~n的所有修改了
因为i前的每一个元素的修改都是对后面所有元素的修改
所以当我们统计i~n的修改的时候 我们需要把前面的修改项都累加起来才行
这里就可以用树状数组统计一下前缀和
也就是当我们对区间s~e修改的时候 用del[s]+add 表示对i~n的修改
但是e之后不要修改 所以我们再执行 del[e+1]-add的操作
这样当我们进行区间修改 单点查询的时候 就用原始a[i]+sum(del[i])【从1-i的信息累加之和】即可表示
当我们需要求区间查询s~e的时候
我们先来看如何求1~i的和
sigma(i) = a[1] + del[1]+ a[2]+ del[1] + del[2] +……+a[i]+del[1]+del[2]+……+del[i]
= a[1]+a[2]+……+a[i] + del[1](i)+del[2] (i-1) +……+del[i] *1
= a[1]+a[2]+……+a[i] + del[1](i-1+1)+del[2] (i-2+1) +……+del[i] *(i-i+1)
= Sigma(a[xi]) + Sigma(del[ xi ]*( i -xi +1 ) )
= Sigma(a[xi]) + Sigma(del[ xi ])* ( i +1 ) ) -Sigma(del[xi] * xi )
可知 第一个Sigma 是静态的 可以用前缀和预处理出来
第二个Sigma: i+1也是不变的 用树状数组统计差分变化 然后求和即可
第三个Sigma: 需要另开辟一个树状数组idel 统计i*del[xi]的前缀和
然后当我们修改区间段的时候 对差分数组del[s]+add 需要同时对 idel[s] + add * s因为最后一个sigma就是表示要把对差分数组的每次修改乘上修改的位置/【下标】
然后在求累加和的时候 自然而然的就把sigma(del[xi]*xi)求出来了
经典例题:
POJ- 3468 A Simple Problem with Integers 线段树区间修改+查询 | 树状数组的区间修改+查询
题意就是经典的两种操作
Q s e 表示查询s到e区间内的总和
C s e add 表示把s到e都加上一个add
区间内的元素大小1e9
区间长度和查询次数1e5
分析:
这道题虽然是课裸的线段树区间修改+查询+延迟标记
但是繁杂的代码不如用实现简单的树状数组来做
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll a[maxn],Sum[maxn],del[maxn],idel[maxn];
// 树状数组 区间更新 区间修改
//维护三个树状数组 1 原始树状数组
// 2 差分树状数组 del
// 3 i*del[i] 的树状数组
int n,m;
void update(ll a[],int x,int add){while(x<=n){a[x]+=add;x+=x&(-x);}
}
ll sum(ll a[],int x){ll s1=0;int tmp = x;while(tmp>0){s1+=a[tmp];tmp-=tmp&(-tmp);}return s1;
}
int main()
{ios::sync_with_stdio(0);cin.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];Sum[i] = Sum[i-1]+a[i];}while(m--){string o;int s,e,add;cin>>o;if(o[0]=='Q'){cin>>s>>e;ll ss = Sum[s-1] + s*sum(del,s-1) - sum(idel,s-1); ll se = Sum[e] + (e+1)*sum(del,e) - sum(idel,e);cout<<se-ss<<endl;}else{cin>>s>>e>>add;//维护区间差分数组 求和时需要用 (x+1)*Sigma(del[x]) update(del,s,add);update(del,e+1,-add);//维护需要减去的 i*del[i]数组 求和时需要减去 Sigma(i*del[i]) update(idel,s,s*add);update(idel,e+1,(e+1)*(-add));}} return 0;
}