/*
LibreOJ-6346线段树-关于时间
一颗线段树难以维护
考虑食用两颗线段树相减
在将操作加入一个列表的时候,我们可以通过线段树维护出他们到最后的贡献
对于任何查询时刻,我们也可以在知道这段区间所有加和与时间的情况下算出他们到最后的贡献
然后两个相减,得到答案
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int n,m,a[N],op;
struct node{
int l,r;
long long val,laz;
}tr1[N*4],tr2[N*4];
void pushdown(node tr[],int u,int fa){
tr[u].val+=tr[fa].laz*(tr[u].r-tr[u].l+1);
tr[u].laz+=tr[fa].laz;
return ;
}
void pd(node tr[],int u){
if(tr[u].laz==0) return ;
pushdown(tr,u<<1,u);pushdown(tr,u<<1|1,u);
tr[u].laz=0;return;
}
void pu(node tr[],int u){
tr[u].val=tr[u<<1].val+tr[u<<1|1].val;
}
void build(node tr[],int u,int l,int r,bool opt){
tr[u]={l,r};
if(l==r){
if(opt) tr[u].val=a[r];
return ;
}
int mid=l+r>>1;
build(tr,u<<1,l,mid,opt);build(tr,u<<1|1,mid+1,r,opt);
if(opt) pu(tr,u);
return ;
}
void upd(node tr[],int u,int l,int r,long long x){
if(l<=tr[u].l && tr[u].r<=r) {
tr[u].val+=x*(tr[u].r-tr[u].l+1);
tr[u].laz+=x;
return ;
}
pd(tr,u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) upd(tr,u<<1,l,r,x);
if(r>mid) upd(tr,u<<1|1,l,r,x);
pu(tr,u);
return ;
}
//注意,这里需要返回longlong,老生常谈了
long long que(node tr[],int u,int l,int r){
if(l<=tr[u].l && tr[u].r<=r) return tr[u].val;
pd(tr,u);
int mid=tr[u].l+tr[u].r>>1;
long long s=0;
if(l<=mid) s=que(tr,u<<1,l,r);
if(r>mid) s+=que(tr,u<<1|1,l,r);
return s;
}
int l,r;long long x;//注意输入流匹配,老生长安了
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
scanf("%d",&m);
build(tr1,1,1,n,1);build(tr2,1,1,n,0);//建树,将原始贡献放在第一棵被减数内
for(int i=1;i<=m;i++){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%lld",&x);
upd(tr1,1,l,r,x*(m-i));upd(tr2,1,l,r,x);
//第一棵直接记录到最后的贡献,第二颗记录要加的
}
else{
printf("%lld\n",que(tr1,1,l,r)-que(tr2,1,l,r)*(m-i));
//到最后的+要加的*到最后的时间即为答案
}
}
return 0;
}
!!!!!!!!!!!!!!!!