首页 > 其他分享 >线段树模板

线段树模板

时间:2023-10-15 20:45:17浏览次数:34  
标签:lc int 线段 tr add rc sum 模板

线段树理解起来不难,主要是书写起来比较麻烦
这里学的是董晓老师的线段树模板

#include<bits/stdc++.h>
using namespace std;
#define lc p<<1
#define rc p<<1|1
#define N 500005
int n,w[N];
struct node
{
    int l,r,sum,add;//add用于懒标记

}tr[N*4];
//建树,深搜递归的过程
void build(int p,int l,int r){
    tr[p]={l,r,w[l]};
    if(l==r){//是最后的叶子节点就返回
        return ;
    } 
    int m=(l+r)>>1;//不是叶子节点就要继续裂开,往下分
    build(lc,l,m);
    build(rc,m+1,r);
    tr[p].sum=tr[lc].sum+tr[rc].sum;

}
//点的修改
void update(int p,int x,int k){//点修改,从根节点进入,递归找到子节点[x,x]
    if(tr[p].l==x&&tr[p].r==x){//叶子节点直接修改
        tr[p].sum+=k;
        return ;
    }
    int m=(tr[p].l+tr[p].r)>>1;//非叶子节点就需要继续往下分,直到到叶子节点
    if(x<=m){
        update(lc,x,k);//在左子树上就进入左子树
    }
    if(x>m){
        update(rc,x,k);//在右子树上就进入右子树,只会进入左右中的一个

    }
    tr[p].sum=tr[lc].sum+tr[rc].sum;

}

//区间查询
int query(int p,int x,int y){//区间查询,从根节点出发
    if(x<=tr[p].l&&tr[p].r<=y){
        return tr[p].sum;
        //如果是这个区间里的就将数据返回,因为肯定是需要加上这段区间
        //覆盖就返回
    }
    int m=(tr[p].l+tr[p].r)>>1;//不覆盖就继续向下裂开
    int sum=0;
    if(x<=m){
        sum+=query(lc,x,y);
    }
    if(y>m){
        sum+=query(rc,x,y);

    }
    return sum; 
}
//区间修改
//懒标记
void pushup(int p){
    tr[p].sum=tr[lc].sum+tr[rc].sum;

}
void pushdown(int p){
    if(tr[p].add){
        tr[lc].sum+=tr[p].add*(tr[lc].r-tr[rc].l+1);//因为是区间每个数都要加一个add
        tr[rc].sum+=tr[p].add*(tr[rc].r-tr[rc].l+1);
        tr[lc].add+=tr[p].add;
        tr[rc].add+=tr[p].add;
        tr[p].add=0;//因为已经将我们做的懒人标记传给下面了,所以之前打的标记就要取消
    }
}
void update1(int p,int x,int y,int k){
    if(x<=tr[p].l&&tr[p].r<=y){//覆盖则修改
        tr[p].sum+=(tr[p].r-tr[p].l+1)*k;
        tr[p].add+=k;
        return ;

    }
    //不覆盖则裂开
    int m=(tr[p].l+tr[p].r)>>1;
    pushdown(p);//向下更新
    if(x<=m){
        update1(lc,x,y,k);

    }
    if(y>m){
        update1(rc,x,y,k);
    }
    pushup(p);//向上更新
}

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>w[i];
    }
    build(1,1,n);//建树
    //之后就是关于一系列的查询与修改

}

标签:lc,int,线段,tr,add,rc,sum,模板
From: https://www.cnblogs.com/du463/p/17766139.html

相关文章

  • 手撕Vue-编译模板数据
    经上一篇编译指令数据后,我们已经可以将指令数据编译成具体需要展示的数据了,上一篇只是编译了指令数据,还没有编译模板数据,这一篇我们就来编译模板数据。也就是{{}}这种模板的形式我们该如何编译,其实和指令数据编译的思路是一样的,废话不多说,直接上代码。改造一下buildText方法......
  • 二分模板
    整数二分边界boolcheck(intx){/*...*/}//检查x是否满足某种性质//区间[l,r]被划分成[l,mid]和[mid+1,r]时使用:intbsearch_1(intl,intr){while(l<r){intmid=l+r>>1;if(check(mid))r=mid;//check()判断mid是......
  • 小程序底层技术机制解读 - 模板引擎
    模板引擎在小程序开发中扮演着关键的角色,它负责将数据渲染到页面上,实现动态的用户界面。本文将深入解读小程序的模板引擎的底层技术机制,以及如何使用它来实现数据和界面的绑定。同时,我们将提供一个简单的代码演示,以帮助读者更好地理解模板引擎的实际应用。小程序模板引擎的作用小程......
  • 手撕Vue-查找指令和模板
    接着上一篇文章,我们已经实现了提取元素到内存的过程,接下来我们要实现的是查找指令和模板。大致的思路是这样的:遍历所有的节点需要判断当前遍历到的节点是一个元素还是一个文本如果是一个元素,我们需要判断有没有v-model属性如果是一个文本,我们需要判断有没有{{}}的内容......
  • *【学习笔记】(7) 线段树及高级用法
    一.普通线段树线段树(SegmentTree)几乎是算法竞赛最常用的数据结构了,它主要用于维护区间信息(要求满足结合律)。与树状数组相比,它可以实现\(O(logn)\)的区间修改,还可以同时支持多种操作(加、乘),更具通用性。接下来我们用这道模板题为例,看看线段树是怎么维护区间和这一信息的。P33......
  • c++ 线段树模板
    洛谷模板:P3372【线段树1】 #include<bits/stdc++.h>#defineintlonglongusingnamespacestd;constintN=1e5+10;inta[N],d[N<<2],b[N<<2];intn,q;inlinevoidbuild(intl,intr,intp){if(l==r){d[p]=a[l];......
  • 模板方法模式
      ......
  • Vue3| 模板引用、defineExpose宏函数
    模板引用的概念:通过ref标识获取真实的dom对象或者组件实例对象 使用:1.调用ref函数生成一个ref对象<script setup>import {ref} from 'vue'const h1Ref=ref(null)</script>2.通过ref标识绑定ref对象到标签<script setup>import {ref......
  • 用户态app Makefile 简易示例模板
    #Makefileforuser-spaceprogramexportPATH=/opt/toolchain/aarch64/bin/:$PATHCC:=aarch64-none-linux-gnu-gccDIR_PATH:=/home/user/sdk-v22.04/test_makefileOTHER_DUND_DIR:=$(DIR_PATH)/test_file_cOTHER_DUND_H:=$(DIR_PATH)/test_file_hCFLAGS:=-......
  • 线段树高阶学习指南
    前置芝士线段树基本框架区间求和constintN=100010;lla[N],st[N*4],f[N*4];intn,q;//向上传voidpushup(llu){st[u]=st[lc]+st[rc];}//向下传voidpushdown(llu,lll,llr,llmid){if(f[u]){st[lc]+=f[u]*(mid-l+1);st[rc]+=f[u]*(r-m......