#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100001;
ll input[N+5];
struct node{ll l,r,sum,lz;}tree[(N<<2)+5];//注意要开四倍空间
inline void build(ll i,ll l,ll r){//递归建树
tree[i].l=l;tree[i].r=r;//赋值
if(l==r){//如果左右区间相同,那么必然是叶子节点,只有叶子节点是被真实赋值的
tree[i].sum=input[l];//赋值
return;//返回上一层
}
ll mid=(l+r)>>1;//二分思想
build(i<<1,l,mid);//建左子树
build(i<<1|1,mid+1,r);//建右子树
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//这个节点等于它的左儿子节点加右儿子节点
}
inline void push_down(ll x){
if(tree[x].lz){
tree[x<<1].l+=tree[x].lz;
tree[x<<1|1].l+=tree[x].lz;//左右儿子分别加上父亲的lz
ll mid=(tree[x].l+tree[x].r)>>1;
tree[x<<1].sum+=tree[x].lz*(mid-tree[x<<1].l+1);
tree[x<<1|1].sum+=tree[x].lz*(tree[x<<1|1].r-mid);//左右分别求和加起来
tree[x].lz=0;//父亲lz归零
}
return;
}
inline void add3(ll i,ll l,ll r,ll val){// i->当前节点 l->目标区间最小节点编号 r->目标区间最大节点编号 val->要增加的值
if(tree[i].l>=l&&tree[i].r<=r){//如果当前区间被完全覆盖在目标区间里
tree[i].sum+=val*(tree[i].r-tree[i].l+1);//将这个区间的sum+k*(tree[i].r-tree[i].l+1)
tree[i].lz+=val;//记录lazytage
return;//返回上一层
}
push_down(i);//向下传递
if(tree[i<<1].r>=l) add3(i<<1,l,r,val);//递归左子树
if(tree[i<<1|1].l<=r) add3(i<<1|1,l,r,val);//递归右子树
tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;//增加左右子树的值
return;//返回上一层
}
inline int find3(ll i,ll l,ll r){//i->当前节点 l->区间最节小点编号 r->区间最大节点编号
if(tree[i].l>=l&&tree[i].r<=r) //如果这个区间被完全被包含在目标区间里面
return tree[i].sum;//直接返回这个区间的值
ll cnt=0;//定义和
if(tree[i].r<l||tree[i].l>r) return cnt;//如果这个区间和要求的区间毫不相干,返回0
push_down(i);
if(tree[i<<1].r>=l) cnt+=find3(i<<1,l,r);//如果这个区间的左儿子和目标区间又交集,那么搜索左儿子
if(tree[i<<1|1].l<=r) cnt+=find3(i<<1|1,l,r);//如果这个区间的右儿子和目标区间又交集,那么搜索右儿子
}
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&input[i]);
build(1,1,n);
for(int i=1;i<=m;++i) {
int x;
cin>>x;
if(x==1){
ll p,q,val;
cin>>p>>q>>val;
add3(1,p,q,val);
}
else{
ll p,q;
cin>>p>>q;
cout<<find3(1,p,q);
}
}
return 0;
}