OIer_dcy__AK_IOI @ 2024-05-20 19:38:21
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e5+10;
struct tree{ //树的结构体
int l,r,sum,add;
/* l是当前节点覆盖区间的左端点
r是右前节点覆盖区间的右端点
sum是当前区间结点的和
add是懒标记
*/
}t[4*N]; //存树
int n,q; //序列长度为n,查询次数q
int a[N]; //a数组存序列
//建树
inline void build(int pos,int l,int r){ //pos为当前节点下标,l为左端点,r为右端点
t[pos].l=l,t[pos].r=r; //当前节点的左端点为l,右端点为r
if(l==r){ //如果是叶子节点(区间长度为1)
t[pos].sum=a[l]; //当前区间的和为节点本身
return ; //回溯
}else{
int mid=(l+r)>>1; //取区间中点
int left=pos<<1; //左子树根节点的下标
int right=pos<<1|1; //右子树根节点的下标
build(left,1,mid); //递归遍历左子树(求左子树的最大值)
build(right,mid+1,r); //递归遍历右子树(求右子树的最大值)
t[pos].sum=t[left].sum+t[right].sum; //当前节点的最大值=左子树最大值+右子树最大值
}
}
////单点修改
//inline void update1(int pos,int x,int k){ //pos为当前节点下标,x为需修改节点的下标,k为将a[x]修改的值
// int l=t[pos].l,r=t[pos].r,mid=(l+r)>>1;
// if(l==x&&r==x){
// t[pos].sum=k;
// }else{
// int left=pos<<1,right=pos<<1|1;
// if(x<=mid){
// update(left,x,k);
// }else{
// update(right,x,k);
// }
// t[pos].sum=t[left].sum+t[right].sum; //修改后当前节点的最大值=修改后左子树最大值+修改后右子树最大值
// }
//}
//向下继承(懒标记的向下更新)
void pushdown(int pos){
int left=pos<<1,right=pos<<1|1;
auto &root= t[pos],&ll=t[left],&rr=t[right];
if(root.add!=0){
ll.add+=root.add;
ll.sum+=(ll.r-ll.l+1)*root.add;
rr.add+=root.add;
rr.sum+=(rr.r-rr.l+1)*root.add;
root.add=0;
}
}
//区间修改
inline void update(int pos,int x,int y,int k){
int l=t[pos].l,r=t[pos].r,mid=(l+1)>>1;
if(x<=l&&y>=r){
t[pos].sum+=(r-l+1)*k;
t[pos].add+=k; //懒标记,子节点还没有更新,在下次查询以及区间修改时更新
}else{
pushdown(pos);
int left=pos<<1,right=pos<<1|1;
if(x<=mid){
update(left,x,y,k);
}
if(y>=mid){
update(right,x,y,k);
}
t[pos].sum=t[left].sum+t[right].sum;
}
}
//查询区间最大值
inline int getsum(int pos,int x,int y){
int l=t[pos].l,r=t[pos].r,mid=(l+r)>>1;
if(x<=l&&y>=r){
return t[pos].sum;
}
pushdown(pos);
int ans=0,left=pos*2,right=pos*2+1;
if(x<=mid){
ans+=getsum(left,x,y);
}
if(y>mid){
ans+=getsum(right,x,y);
}
return ans;
}
signed main(){
//输入
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
build(1,1,n); //建树
while(q--){ //q次查询(修改)
int op;
scanf("%lld",&op);
if(op==1){ //区间修改
int x,y,d;
scanf("%lld%lld%lld",&x,&y,&d);
update(1,x,y,d);
}else if(op==2){ //区间查询
int x,y;
scanf("%lld%lld",&x,&y);
printf("%lld\n",getsum(1,x,y));
}
}
return 0;
}