区间加上一个等差数列这件事情其实并不好维护。但既然是单点查询,那就可以考虑差分。
我们考虑将数列差分,维护一个差分数列。于是区间 [l,r] 加上等差数列 {K,D},就变成了三个操作:
点 l 加上 K
区间 [l+1,r] 加上 D
点 r+1 减去 K+(r-l)*D
对于每个查询求前缀和即可。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100005;
int n,m;
ll a[N];
ll val[N<<2],tag[N<<2];
inline void pshd(int L,int R,int X){
int MID=(L+R)>>1;
tag[X<<1]+=tag[X];tag[X<<1|1]+=tag[X];
val[X<<1]+=tag[X]*(MID-L+1);val[X<<1|1]+=tag[X]*(R-MID);
tag[X]=0;
}
inline void updt(int X){
val[X]=val[X<<1]+val[X<<1|1];
}
ll qry(int L,int R,int A,int B,int X){
if(A<=L&&B>=R){
return val[X];
}
int MID=(L+R)>>1;ll ret=0;
pshd(L,R,X);
if(A<=MID){
ret+=qry(L,MID,A,B,X<<1);
}
if(B>MID){
ret+=qry(MID+1,R,A,B,X<<1|1);
}
return ret;
}
void mdf(int L,int R,int A,int B,int X,ll V){
if(A<=L&&B>=R){
tag[X]+=V;
val[X]+=V*(R-L+1);
return;
}
int MID=(L+R)>>1;
pshd(L,R,X);
if(A<=MID){
mdf(L,MID,A,B,X<<1,V);
}
if(B>MID){
mdf(MID+1,R,A,B,X<<1|1,V);
}
updt(X);
}
void build(int L,int R,int X){
if(L==R){
val[X]=a[L];
return;
}
int MID=(L+R)>>1;
build(L,MID,X<<1);
build(MID+1,R,X<<1|1);
updt(X);
}
inline void chg(int L,int R,ll V){
if(L>R||L<1||R>n){
return;
}
mdf(1,n,L,R,1,V);
}
inline void init(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
for(int i=n;i>1;--i){
a[i]-=a[i-1];
}
build(1,n,1);
ll opt,l,r,k,d,p;
for(int i=1;i<=m;++i){
scanf("%lld",&opt);
if(opt==1){
scanf("%lld%lld%lld%lld",&l,&r,&k,&d);
chg(l,l,k);chg(l+1,r,d);chg(r+1,r+1,-(k+d*(r-l)));
}else{
scanf("%lld",&p);
printf("%lld\n",qry(1,n,1,p,1));
}
}
}
int main(){
init();
return 0;
}