首页 > 其他分享 >线段树+懒标记 (区间修改,区间查询)

线段树+懒标记 (区间修改,区间查询)

时间:2024-08-14 20:28:18浏览次数:8  
标签:标记 int 线段 tr build 区间 include LL change

原作者:董晓


P3372 【模板】线段树 1

// 结构体版
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define N 100005
#define LL long long
#define lc u<<1
#define rc u<<1|1
LL w[N];
struct Tree{ //线段树
  LL l,r,sum,add;
}tr[N*4];

void pushup(LL u){ //上传
  tr[u].sum=tr[lc].sum+tr[rc].sum;
}
void pushdown(LL u){ //下传
  if(tr[u].add){
    tr[lc].sum+=tr[u].add*(tr[lc].r-tr[lc].l+1),
    tr[rc].sum+=tr[u].add*(tr[rc].r-tr[rc].l+1),
    tr[lc].add+=tr[u].add,
    tr[rc].add+=tr[u].add,
    tr[u].add=0;      
  }
}
void build(LL u,LL l,LL r){ //建树
  tr[u]={l,r,w[l],0};
  if(l==r) return;
  LL m=l+r>>1;
  build(lc,l,m);
  build(rc,m+1,r);
  pushup(u);
}
void change(LL u,LL l,LL r,LL k){ //区修
  if(l<=tr[u].l&&tr[u].r<=r){
    tr[u].sum+=(tr[u].r-tr[u].l+1)*k;
    tr[u].add+=k;
    return;
  }
  LL m=tr[u].l+tr[u].r>>1;
  pushdown(u);
  if(l<=m) change(lc,l,r,k);
  if(r>m) change(rc,l,r,k);
  pushup(u);
}
LL query(LL u,LL l,LL r){ //区查
  if(l<=tr[u].l && tr[u].r<=r) return tr[u].sum;
  LL m=tr[u].l+tr[u].r>>1;
  pushdown(u);
  LL sum=0;
  if(l<=m) sum+=query(lc,l,r);
  if(r>m) sum+=query(rc,l,r);
  return sum;
}
int main(){
  int n,m,op,x,y,k;  
  cin>>n>>m;
  for(int i=1; i<=n; i ++) cin>>w[i];
  
  build(1,1,n);
  while(m--){
    cin>>op>>x>>y;
    if(op==2)cout<<query(1,x,y)<<endl;
    else cin>>k,change(1,x,y,k);
  }
  return 0;
}

P3374 【模板】树状数组 1

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define lc u<<1
#define rc u<<1|1
#define N 500005
int w[N];
struct Tree{
  int l,r,sum;
}tr[N*4];

void pushup(int u){ //上传
  tr[u].sum=tr[lc].sum+tr[rc].sum;
}
void build(int u,int l,int r){ 
  tr[u]={l,r,w[l]};
  if(l==r) return;
  int m=l+r>>1;
  build(lc,l,m);
  build(rc,m+1,r);
  pushup(u);
}
void change(int u,int x,int k){ //点修
  if(tr[u].l==x&&tr[u].r==x){
    tr[u].sum+=k;
    return;
  }
  int m=tr[u].l+tr[u].r>>1;
  if(x<=m) change(lc,x,k);
  if(x>m) change(rc,x,k);
  pushup(u);
}
int query(int u,int l,int r){ //区查
  if(l>tr[u].r || r<tr[u].l) return 0;
  if(l<=tr[u].l&&tr[u].r<=r) return tr[u].sum;
  return query(lc,l,r)+query(rc,l,r);
}
int main(){
  ios::sync_with_stdio(0);
  int n,m,op,x,y;  
  cin>>n>>m;
  for(int i=1;i<=n;i++) cin>>w[i];
  build(1,1,n);
  while(m--){
    cin>>op>>x>>y;
    if(op==1) change(1,x,y);
    else cout<<query(1,x,y)<<endl;
  }
  return 0;
}

P3368 【模板】树状数组 2

#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define N 500005
#define LL long long
#define lc u<<1
#define rc u<<1|1
LL w[N];
struct Tree{ //线段树
  LL l,r,sum,add;
}tr[N*4];

void pushup(LL u){ //上传
  tr[u].sum=tr[lc].sum+tr[rc].sum;
}
void pushdown(LL u){ //下传
  if(tr[u].add){
    tr[lc].sum+=tr[u].add*(tr[lc].r-tr[lc].l+1),
    tr[rc].sum+=tr[u].add*(tr[rc].r-tr[rc].l+1),
    tr[lc].add+=tr[u].add,
    tr[rc].add+=tr[u].add,
    tr[u].add=0;      
  }
}
void build(LL u,LL l,LL r){ //建树
  tr[u]={l,r,w[l],0};
  if(l==r) return;
  LL m=l+r>>1;
  build(lc,l,m);
  build(rc,m+1,r);
  pushup(u);
}
void change(LL u,LL x,LL y,LL k){ //区修
  if(x>tr[u].r || y<tr[u].l) return;
  if(x<=tr[u].l && tr[u].r<=y){
    tr[u].sum+=(tr[u].r-tr[u].l+1)*k;
    tr[u].add+=k;
    return;
  }
  pushdown(u);
  change(lc,x,y,k); 
  change(rc,x,y,k);
  pushup(u);
}
LL query(LL u,LL x){ //点查
  if(x>tr[u].r || x<tr[u].l) return 0;
  if(x==tr[u].l && tr[u].r==x) return tr[u].sum;
  pushdown(u);
  return query(lc,x)+query(rc,x);
}
int main(){
  ios::sync_with_stdio(0);
  int n,m,op,x,y,k;  
  cin>>n>>m;
  for(int i=1; i<=n; i ++) cin>>w[i];
  
  build(1,1,n);
  while(m--){
    cin>>op>>x;
    if(op==2)cout<<query(1,x)<<endl;
    else cin>>y>>k,change(1,x,y,k);
  }
  return 0;
}

标签:标记,int,线段,tr,build,区间,include,LL,change
From: https://www.cnblogs.com/swjswjswj/p/18359706

相关文章

  • ST表 RMQ问题(区间最大/最小值查询)
    #include<iostream>#include<cstring>#include<algorithm>#include<cmath>usingnamespacestd;intf[100005][22];intmain(){intn,m;scanf("%d%d",&n,&m);for(inti=1;i<=n;i++)scanf("%d"......
  • 李超线段树
    用途:用于二维坐标系维护多条线段。算法:本质上是采用标记永久化,对每个线段树节点维护一个标记表示该区间存在这一条线段,查询时从上到下经过节点的标记即为该横坐标上可能经过的线段。下面需在标记(线段)间的比较上作考虑:建议画图理解此时对于一个区间\([l,r]\),找出中点\(mid......
  • 0228-TCP 的标记和选项
    环境Time2022-11-24WSL-Ubuntu22.04Rust1.65.0pnet0.31.0tun-tap0.1.3前言说明参考:https://docs.rs/pnet/latest/pnet/index.html参考:https://www.cnblogs.com/lshs/p/6038494.html目标了解TCP协议头中的flags和options字段的含义。main.rsusepnet::pa......
  • 2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始
    2024-08-14:用go语言,给定两个长度分别为n和m的整数数组nums和changeIndices,下标从1开始。初始时,nums中所有下标均未标记。从第1秒到第m秒,每秒可以选择以下四种操作之一:1.选择范围[1,n]中一个下标i,将nums[i]减少1。2.将nums[changeIndices[s]]设为任意非负整数。3.选择范围......
  • unity中, 二维平面上,求从点A出发,沿着方向B,与线段C的交点
    代码说明:点A:起始点。方向B:一个方向向量,表示从点A出发的方向。线段C:由两个点C1和C2定义。1usingUnityEngine;23publicclassLineIntersection:MonoBehaviour4{5//返回从点A出发,沿着方向B,与线段C的交点。如果没有交点,则返回null6publicstati......
  • 可持久化线段————主席树(洛谷p3834)
    洛谷P3834可持久化线段树2问题描述:给定n各整数构成的序列,求指定区间[L,R]内的第k小值(求升序排序后从左往右数第k个整数的数值)输入:第一行输入两个整数n,m,分别代表序列长度n和对序列的m次查询;第二行输入n个整数,表示序列的n个整数;之后的m行,每行输入3个整数L,R,k,表示查询......
  • 线段树
    模板记得开4倍空间!!!Code#include<bits/stdc++.h>#definelllonglong#definepfprintf#definesfscanfusingnamespacestd;constintN=1e5+7;inttr[N*4];intf[N*4];inta[N];intn,q;intl,r,val;voidbuild(intu,intl,intr){ if(l==r){ tr[u]=a......
  • 【笔记】吉如一线段树
    【笔记】吉如一线段树吉如一论文(CQBZ内网,在PDF的103页1区间最值操作1.1区间取min(max),区间和当前应该修改值为\(x\);维护区间最大值\(mx\),最大值个数\(t\),严格次大值\(se\)。如果走到一个区间上,如果:\(x\gemx\),说明取min操作没用,直接return;\(mx>x>se\),打标......
  • 李超线段树板子
    点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintN=1e6+5;constintmod=1e9;constintp=39989;constdoubleeps=1e-9;intn,m;intans,ansid;inttcnt,rt;structlmy{ doublek,b;}a[N];structTree{ intls,rs,id;}tr[N];boolc......
  • 【笔记】传统势能线段树
    1引入传统线段树能够通过打标记实现区间修改的条件有两个:能够快速处理标记对区间询问结果的影响;能够快速实现标记的合并。有的区间修改不满足上面两个条件。但存在一些奇妙的性质,使得序列每个元素被修改的次数有一个上限。如果我们保证每暴力\(O(\logn)\)修改一次的时......