分块维护一个区间和
然后记得更新的时候左边角块的tag不要打错到右边角块
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
long long sz,num,n,belong[],a[],sum[],tag[];
void calbe(int n){
for(int i=;i<=n;i++)
belong[i]=(i-)/sz+;
}
void reset(int x){
sum[x]=;
for(int i=(x-)*sz+;i<=min(x*sz,n);i++)
sum[x]+=a[i];
}
void update(int l,int r,int w){
int xl=belong[l];
int xr=belong[r];
for(int i=l;i<=min(xl*sz,(long long)r);i++){
a[i]+=w;
sum[xl]+=w;
}
if(xl!=xr){
for(int i=(xr-)*sz+;i<=r;i++){
a[i]+=w;
sum[xr]+=w;
}
}
for(int i=xl+;i<=xr-;i++){
tag[i]+=w;
}
}
long long query(int l,int r,int w){
int xl=belong[l];
int xr=belong[r];
long long ans=;
for(int i=l;i<=min(xl*sz,(long long)r);i++)
ans=(ans%w+(a[i]+tag[xl])%w)%w;
if(xl!=xr){
for(int i=(xr-)*sz+;i<=r;i++)
ans=(ans%w+(a[i]+tag[xr])%w)%w;
}
for(int i=xl+;i<=xr-;i++)
ans=(ans%w+(sum[i]+(tag[i]*sz))%w)%w;
return ans;
}
int main(){
scanf("%lld",&n);
sz=sqrt(n);
num=n/sz;
calbe(n);
if(n%sz)
num++;
for(int i=;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=;i<=num;i++)
reset(i);
// for(int i=1;i<=num;i++)
// printf("%d\n",sum[i]);
for(int i=;i<=n;i++){
int opt,l,r,c;
scanf("%d %d %d %d",&opt,&l,&r,&c);
if(opt==)
update(l,r,c);
else
printf("%lld\n",query(l,r,c+));
}
return ;
}