A simple problem with integer 树状数组区间查询模板题 contest 树状数组练习 T1
Description
给定一个长为n的序列,接下来m次操作,每次操作会对序列某段区间内所有数加上一个值,或是询问一段区间的和。
Input
第一行,n和m,代表序列长度为n,并有m个操作第二行有n个数字,表示序列中的每个元素接下来m行,每行形如Q a b代表查询[a,b]的区间和,或C a b c代表对[a,b]中的所有数都增加c。
Output
每行输出对应每一个查询的结果。
Hint
n,m<=100000。
Solution
同样维护一个差分数组,可以推得一段区间和的表达式就是(x+1)*sigma(d[i])-ixsigma(d[i])。用两个树状数组分别维护d[i]和d[i]xi,不过需要注意的是,维护d[i]xi的时候,修改值或者查询乘的是原本的x值而不是x+-lowbit(x)的值。
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#define maxn 100005
#define lowbit(x) (x&(-x))
#define int long long
using namespace std;
int c1[maxn],c2[maxn],a[maxn],d[maxn];
int n,m,x,y,w,z;
char tmp[maxn];
void init(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
}
void doadd(int x,int dd){
int f=x;
while(x<=n){
c1[x]+=dd;
c2[x]+=f*dd;
x+=lowbit(x);
}
}
int dofinD(int x){
int ans=0,f=x;
while(x>0){
ans+=(f+1)*c1[x]-c2[x];
x-=lowbit(x);
}
return ans;
}
void set_d(){
for(int i=1;i<=n;i++){
d[i]=a[i]-a[i-1];
}
for(int i=1;i<=n;i++){
doadd(i,d[i]);
}
}
signed main(){
init();
set_d();
for(int i=1;i<=m;i++){
scanf("%s",tmp);
if(tmp[0]=='Q'){
scanf("%lld%lld",&x,&y);
printf("%lld\n",dofinD(y)-dofinD(x-1));
}
else if(tmp[0]=='C'){
scanf("%lld%lld%lld",&x,&y,&w);
doadd(x,w);
doadd(y+1,-w);
}
}
return 0;
}