我们知道,线段树用来做单点修改是很方便的,那么,既然这么方便,为什么不能用它来做区间修改呢?好吧,我们来试试看:
首先不难想到要把区间修改转化为前缀修改,即,将把
[L,R]
这段区间加
k
,变成把
那么我们来考虑如何维护这个东西,考虑
显然需要分两种情况讨论:
1∘i<x
对于这样的 Ai ,显然它会增加 i∗k
2∘i≤x
对于这样的 Ai ,显然它会增加 x∗k
接下来我们来考虑如何求
Ai
,显然,我们需要把上述两种情况进行相加得到真正的
Ai
,考虑第一种情况,现在我们要求的是所有大于
i
的
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define lowbit(x) (x&-x)
#define LL long long
using namespace std;
inline char nc(){
static char buf[100000],*i=buf,*j=buf;
return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline LL _read(){
char ch=nc();LL sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
}
int n,tet;
LL a[maxn],f1[maxn],f2[maxn];
void put1(int x,LL y){for(;x<=n;x+=lowbit(x))f1[x]+=y;}
LL get1(int x){
if(x<0)return 0;
int sum=0;
for(;x;x-=lowbit(x))sum+=f1[x];
return sum;
}
void put2(int x,LL y){for(;x<=n;x+=lowbit(x))f2[x]+=y;}
LL get2(int x){
if(x<0)return 0;
LL sum=0;
for(;x;x-=lowbit(x))sum+=f2[x];
return sum;
}
void put(int l,int r,LL k){
if(l>1)put1(l-1,-k),put2(l-1,(1-l)*k);
put1(r,k);put2(r,r*k);
}
LL get(int x){return x*(get1(n)-get1(x))+get2(x);}
int main(){
freopen("temp.in","r",stdin);
freopen("temp.out","w",stdout);
n=_read();tet=_read();
for(int i=1;i<=n;i++) a[i]=a[i-1]+_read();
while(tet--){
int k=_read();
if(k==1){
int l=_read(),r=_read(),x=_read();
put(l,r,x);
}else{
int l=_read(),r=_read();
printf("%lld\n",a[r]-a[l-1]+get(r)-get(l-1));
}
}
return 0;
}