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

视频链接:265 线段树+标记永久化 区修+区查 Luogu P3372 线段树 1_哔哩哔哩_bilibili

 

 

Luogu P3372【模板】线段树 1 

// 线段树+标记永久化 O(M*logN)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

#define ls u<<1
#define rs u<<1|1
#define mid ((l+r)>>1)
const int N=100005;
typedef long long LL;
int n,m,a[N];
LL sum[N*4],tag[N*4]; //区间和,永久标记

void build(int u,int l,int r){ //建树
  sum[u]=a[l];
  if(l==r) return;
  build(ls,l,mid);
  build(rs,mid+1,r);
  sum[u]=sum[ls]+sum[rs];
}
void change(int u,int l,int r,int x,int y,LL k){ //区修
  sum[u]+=(min(r,y)-max(x,l)+1)*k;  //经过节点更新sum
  if(x<=l&&r<=y){tag[u]+=k;return;} //覆盖节点更新tag
  if(x<=mid) change(ls,l,mid,x,y,k);
  if(y>mid) change(rs,mid+1,r,x,y,k);
}
LL query(int u,int l,int r,int x,int y,LL s){ //区查
  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+=query(ls,l,mid,x,y,s);
  if(y>mid) res+=query(rs,mid+1,r,x,y,s);
  return res;
}
int main(){
  scanf("%d%d",&n,&m);
  for(int i=1;i<=n;i++) scanf("%d",&a[i]);
  build(1,1,n);
  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),change(1,1,n,x,y,k);
    else printf("%lld\n",query(1,1,n,x,y,0));
  }
}

 

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