本文章适合已经会基本的树状数组用法看。
树状数组最经常的两个操作:单点更新,区间求和
如果要区间更新怎么办?
参考文章:https://www.cnblogs.com/kickit/p/9172189.html
(问题一)给定数组 a,有 2 种操作
- 将区间 [l,r] 的 a 加上 v
- 求区间
解法上面博客已经说明,就不再加以说明。
(问题二)给定数组a,b;有 2 种操作,
-
将区间 [l,r] 的 a 加上 v
-
求
分析:
该问题直接差分是不行的,因为多了一个权值b,然而因为要进行区间修改操作,我们依然可以先化成差分的形式。
设
=
这个式子直观上不太好看,我考虑将他拆开(数学太差,只能靠肉眼观察QaQ)
=
肉眼发现将 d 提出来会得到一个有意思的东西
=
设
上式
=
=
=
则该式子和问题1的式子变得一模一样,该问题就解决了。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int a[N],s[N],val1[N],val2[N],n;
//树状数组部分, val1维护d , val2维护 di * si-1
inline int lowbit(int x){
return x&(-x);
}
void update(int x,int v,int *val){
for(int i=x;i<=n;i+=lowbit(i))
val[i]+=v;
}
int sum(int x,int *val){
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans+=val[i];
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){ //设a的初始值为0,这里输入的是b
int x;
scanf("%d",&s[i]);
s[i]+=s[i-1];
}
int m;
scanf("%d",&m);
while(m--){
int op,x,y,v;
scanf("%d%d%d",&op,&x,&y);
if(op==1) {
scanf("%d",&v);
update(x,v,val1);
update(y+1,-v,val1);
update(x,v*s[x-1],val2);
update(y+1,-v*s[y],val2);
} else {
int ans;
ans = s[y] *sum(y,val1) - sum(y,val2);
ans-= s[x-1]*sum(x-1,val1) - sum(x-1,val2);
printf("%d\n",ans);
}
}
return 0;
}
/**给出一组测试数据
6
1 2 3 4 5 6
4
1 2 3 3
2 3 4
1 1 5 3
2 2 6
*/