动态开点线段树
#include<iostream>
#include<cstdio>
#define ri register int
#define u long long
namespace opt {
inline u in() {
u x(0),f(1);
char s(getchar());
while(s<'0'||s>'9') {
if(s=='-') f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=(x<<1)+(x<<3)+s-'0';
s=getchar();
}
return x*f;
}
}
using opt::in;
#define NN 100005
namespace xds {
struct node{
u l,r,sum,add;
}a[NN<<1];
u num,root;
void pushdown(const u &rt,const u &l,const u &r){
if(a[rt].add){
if(!a[rt].l) a[rt].l=++num;
if(!a[rt].r) a[rt].r=++num;
u mid((l+r)>>1);
a[a[rt].l].add+=a[rt].add;
a[a[rt].r].add+=a[rt].add;
a[a[rt].l].sum+=a[rt].add*(mid-l+1);
a[a[rt].r].sum+=a[rt].add*(r-mid);
a[rt].add=0;
}
}
void update(u &rt,const u &l,const u &r,const u &x,const u &y,const u &k){
if(!rt) rt=++num;
if(l>=x&&r<=y){
a[rt].sum+=k*(r-l+1),a[rt].add+=k;
return;
}
pushdown(rt,l,r);
u mid((l+r)>>1);
if(x<=mid) update(a[rt].l,l,mid,x,y,k);
if(y>=mid+1) update(a[rt].r,mid+1,r,x,y,k);
a[rt].sum=a[a[rt].l].sum+a[a[rt].r].sum;
}
u query(const u &rt,const u &l,const u &r,const u &x,const u &y){
if(!rt) return 0;
if(l>=x&&r<=y) return a[rt].sum;
pushdown(rt,l,r);
u mid((l+r)>>1),_re(0);
if(x<=mid) _re+=query(a[rt].l,l,mid,x,y);
if(y>=mid+1) _re+=query(a[rt].r,mid+1,r,x,y);
return _re;
}
}
namespace mainstay {
inline void solve(){
u N(in()),M(in()),_a;
for(ri i(1);i<=N;++i) _a=in(),xds::update(xds::root,1,N,i,i,_a);
for(ri i(1);i<=M;++i){
u k(in());
if(k==1){
u l(in()),r(in()),_x(in());
xds::update(xds::root,1,N,l,r,_x);
}
else{
u l(in()),r(in());
printf("%lld\n",xds::query(xds::root,1,N,l,r));
}
}
}
}
int main() {
//freopen("x.txt","r",stdin);
std::ios::sync_with_stdio(false);
mainstay::solve();
}