RE求调

P3372 【模板】线段树 1

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;
}

|