const int maxn=1e5+7,mod=1e9+7,inf=0x3f3f3f3f;
int n,m,root[maxn],idx;
ll a[maxn];
struct node{
int l,r;
ll sum,laz;
}tr[maxn*32];
void pushup(int u,int l,int r){
tr[u].sum=tr[tr[u].l].sum+tr[tr[u].r].sum+tr[u].laz*(r-l+1);
}
void build(int &now,int l,int r){
now=++idx;//建立新线段树
tr[now].sum=tr[now].laz=0;
if(l==r){
tr[now].sum=a[l];return ;///初始化
}
int mid=(l+r)/2;
build(tr[now].l,l,mid);build(tr[now].r,mid+1,r);
pushup(now,l,r);
}
void update(int &now,int las,int l,int r,int L,int R,int val){
now=++idx;///对于修改的节点新建立一颗树
tr[now]=tr[las];//先复制过来
if(L<=l&&r<=R){//当前区间完全包含待修改区间的话
tr[now].laz+=val;//永久化标记
tr[now].sum+=val*(r-l+1);//求和
return ;///及时返回 已经更新完了 不需要pushup操作
}
int mid=(l+r)/2;
if(L<=mid) update(tr[now].l,tr[las].l,l,mid,L,R,val);
if(R>mid) update(tr[now].r,tr[las].r,mid+1,r,L,R,val);
pushup(now,l,r);
}
ll query(int now,int l,int r,int L,int R,ll add){
//add为路径上的懒惰标记
if(L<=l&&r<=R){
return tr[now].sum+add*(r-l+1);///完全包含的话,值等于和加上标记的内容
}
ll ans=0;
int mid=(l+r)/2;
if(L<=mid) ans+=query(tr[now].l,l,mid,L,R,add+tr[now].laz);//注意沿途加标记
if(R>mid) ans+=query(tr[now].r,mid+1,r,L,R,add+tr[now].laz);
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
idx=0;
int time=0;
rep(i,1,n) a[i]=read;
build(root[0],1,n);
rep(i,1,m){
char op[2];
cin>>op;
if(op[0]=='C'){
int l=read,r=read,d=read;
++time;
update(root[time],root[time-1],1,n,l,r,d);
}
else if(op[0]=='Q'){
int l=read,r=read;
printf("%lld\n",query(root[time],1,n,l,r,0));
}
else if(op[0]=='H'){
int l=read,r=read,t=read;
printf("%lld\n",query(root[t],1,n,l,r,0));
}
else time=read;
}
}
return 0;
}