C79【模板】线段树+标记永久化 区修+区查 Luogu P3372 线段树 1

C79 线段树+标记永久化 区修+区查 Luogu P3372 线段树 1_哔哩哔哩_bilibili

 

标记永久化

修改时留下的懒标记(tag)并不下传,也不删除,而是留在打上标记的那一个节点上

当查询经过这个节点时,就加上这个节点的懒标记造成的影响

标记永久化 不需要 pushdown 和 pushup

image

image

相关板子:

C02【模板】线段树+懒标记 P3372 线段树 1 - 董晓 - 博客园

 

P3372 【模板】线段树 1 - 洛谷

// 线段树+标记永久化 O(M*logN)
#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=100005;
int n,m; LL a[N];

struct SGT{ //线段树
  #define ls u<<1
  #define rs u<<1|1
  #define mid ((l+r)>>1)
  LL sum[N*4],tag[N*4]; //区间和,永久标记
  
  void build(int u=1,int l=1,int r=n){ //建树
    sum[u]=a[l];
    if(l==r) return;
    build(ls,l,mid);
    build(rs,mid+1,r);
    sum[u]=sum[ls]+sum[rs];
  }
  void upd(int x,int y,LL k,int u=1,int l=1,int r=n){ //区修
    sum[u]+=(min(r,y)-max(x,l)+1)*k;  //经过节点更新sum
    if(x<=l&&r<=y){tag[u]+=k;return;} //覆盖节点更新tag
    if(x<=mid) upd(x,y,k,ls,l,mid);
    if(y>mid) upd(x,y,k,rs,mid+1,r);
  }
  LL ask(int x,int y,LL s,int u=1,int l=1,int r=n){ //区查
    if(x<=l&&r<=y)return sum[u]+(min(r,y)-max(x,l)+1)*s; //覆盖即返回
    LL res=0; s+=tag[u]; //累计标记,下传给儿子
    if(x<=mid) res+=ask(x,y,s,ls,l,mid);
    if(y>mid) res+=ask(x,y,s,rs,mid+1,r);
    return res;
  }
}T;

int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
  
  T.build();
  int op,x,y; LL k;
  for(int i=1;i<=m;i++){
    scanf("%d%d%d",&op,&x,&y);
    if(op==1) scanf("%lld",&k),T.upd(x,y,k);
    else printf("%lld\n",T.ask(x,y,0));
  }
}
 

 

posted @ 2023-12-22 22:06  董晓  阅读(254)  评论(0)    收藏  举报