#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int N=4567898;
ll a[N],ans[N],tag[N];
ll k,n,m;
ll ltree(ll root);
ll rtree(ll root);
void push_up(ll root);
void push_down(ll root,ll left_,ll right_);
void build(ll root,ll left_,ll right_);
void add(ll left_,ll right_,ll root,ll k);
ll query(ll qul,ll qur,ll left_,ll right_,ll root);
void work(ll addl,ll addr,ll left_,ll right_,ll root,ll k);
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
build(1,1,n);
ll flag,l,r;
for(int i=1;i<=m;i++)
{
scanf("%lld%lld%lld",&flag,&l,&r);
switch(flag)
{
case 1:
{
scanf("%lld",&k);
work(l,r,1,n,1,k);
break;
}
case 2:
{
printf("%lld\n",query(l,r,1,n,1));
break;
}
}
}
return 0;
}
void work(ll addl,ll addr,ll left_,ll right_,ll root,ll k)//区间修改操作
{
if(addl<=left_&&addr>=right_)//目标区间完全覆盖x的控制区间
{
tag[root]+=k;//懒标记+
ans[root]+=k*(right_-left_+1);//区间和+
return ;
}
push_down(root,left_,right_);//懒标记下放
ll mid=(left_+right_)/2;
if(addl<=mid)//左子树含有目标区间
work(addl,addr,left_,mid,ltree(root),k);
if(addr>mid)//右子树含有目标区间
work(addl,addr,mid+1,right_,rtree(root),k);
push_up(root);//更新父节点区间和
}
void build(ll root,ll left_,ll right_)//建树
{
tag[root]=0;
if(left_==right_)
{
ans[root]=a[left_];//把值赋给区间和
return ;
}
ll mid=(left_+right_)/2;//把区间分成两半
build(ltree(root),left_,mid);
build(rtree(root),mid+1,right_);
push_up(root);//区间和数组初始化
return ;
}
ll ltree(ll root)
{
return root<<1;
}
ll rtree(ll root)
{
return root<<1|1;
}
void push_up(ll root)//区间和向上传递
{
ans[root]=ans[ltree(root)]+ans[rtree(root)];
//父节点区间和等于左右区间和
return;
}
void push_down(ll root,ll left_,ll right_)//懒标记下放
{
ll mid=(left_+right_)/2;
add(left_,mid,ltree(root),tag[root]);//左子树数据修改
add(mid+1,right_,rtree(root),tag[root]);//右子树数据修改
tag[root]=0;//下放之后父节点懒标记清零
return;
}
void add(ll left_,ll right_,ll root,ll k)
{
tag[root]+=k;
ans[root]+=k*(right_-left_+1);
return;
}
ll query(ll qul,ll qur,ll left_,ll right_,ll root)
{//区间查询
if(qul<=left_&&qur>=right_)//要查询的区间已经完全覆盖x控制区间
return ans[root];//直接返回x区间和
ll s=0;//x控制范围内查询的结果
ll mid=(left_+right_)/2;
push_down(root,left_,right_);//父节点懒标记下放
if(qul<=mid)//左子树包含目标区间
s+=query(qul,qur,left_,mid,ltree(root));
if(qur>=mid)//右子树包含目标区间
s+=query(qul,qur,mid+1,right_,rtree(root));
return s;
}