线段树(线段树入门笔记)

简介: 线段树(线段树入门笔记)

什么是线段树
线段树是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
对于线段树中的每一个非叶节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。
在这里插入图片描述
定义结点
一般定义成结构体类型,其成员可以根据需要增加

struct node{
   
   
    int l;//左区间端点 
    int r;//右区间端点 
    int val;//此节点存值 
    int len;//子结点管理区间长度 
}tree[1005];

建树

void build(int cur, int l, int r)
{
   
   
    int mid=(l+r)/2;
    tree[cur].l=l, tree[cur].r=r;
    tree[cur].val=0, tree[cur].len=r-l+1;
    if (l==r)//只有到达叶结点时才把数组的值赋给它 
        tree[cur].val=arr[l];//arr为输入数据的数组
    else{
   
   
        build(cur*2, l, mid);
        build(cur*2+1, mid+1, r);
        tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;//回溯过程中更新父结点 
    }
}

单点更新

void updata(int cur, int id, int val)//cur为节点编号,id为修改数据的编号,val为增加的值 
{
   
   
    int l=tree[cur].l, r=tree[cur].r;
    int mid=(l+r)/2;
    if (l==r){
   
   
        tree[cur].val+=val;
        return;
    }
    if (id<=mid)
        updata(cur*2, id, val);
    else
        updata(cur*2+1, id, val);
    tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;//回溯过程中更新父结点 
}

区间查询

int query(int cur, int ql, int qr)
{
   
   
    int l=tree[cur].l, r=tree[cur].r;
    int mid=(l+r)/2, res=0;
    if (ql<=l && r<=qr)//如果此节点的区间在查询区间内,直接返回 
        return tree[cur].val;
    if (ql<=mid)
        res+=query(cur*2, ql, qr);
    if (qr>mid)//注意这里是两个if,不是分支关系 
        res+=query(cur*2+1, ql, qr);
    return res;
}

完整模板

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

struct node{
   
   
    int l;
    int r;
    int val;
    int len;
    int lazy;
}tree [505];
int arr[505];

void pushup(int cur){
   
   
    tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;
}

void pushdown(int cur){
   
   
    if (tree[cur].lazy!=0){
   
   
        tree[cur*2].lazy+=tree[cur].lazy;
        tree[cur*2+1].lazy+=tree[cur].lazy;
        tree[cur*2].val+=tree[cur*2].len*tree[cur].lazy;
        tree[cur*2+1].val+=tree[cur*2+1].len*tree[cur].lazy;
        tree[cur].lazy=0;
    }
}
//建树 
void build(int cur, int l, int r){
   
   
    int mid=(l+r)/2;
    tree[cur].l=l, tree[cur].r=r;
    tree[cur].val=0, tree[cur].len=r-l+1;
    tree[cur].lazy=0;
    if (l==r)
        tree[cur].val=arr[l];
    else{
   
   
        build(cur*2, l, mid);
        build(cur*2+1, mid+1, r);
        pushup(cur);
    }
}

//单点更新  加值 
void update_point(int cur, int pos, int val)//cur为节点编号,id为修改数据的编号,val为增加的值 
{
   
   
    int l=tree[cur].l, r=tree[cur].r;
    int mid=(l+r)/2;
    if (l==r){
   
   
        tree[cur].val+=val;
        tree[cur].lazy+=val;
        return;
    }
    if (pos<=mid)
        update_point(cur*2, pos, val);
    else
        update_point(cur*2+1, pos, val);
    pushup(cur);
} 
//单点查询
int query_point(int cur, int pos){
   
   
    if (tree[cur].l==tree[cur].r)
        return tree[cur].val;
    pushdown(cur);

    int mid=(tree[cur].l+tree[cur].r)/2;
    if (pos<mid)
        query_point(cur*2, pos);
    else
        query_point(cur*2+1, pos);
} 
//区间查询
int query_interval(int cur, int ql, int qr){
   
   
    if (ql<=tree[cur].l && tree[cur].r<=qr)
        return tree[cur].val;
    pushdown(cur);

    int ans=0;
    int mid=(tree[cur].l+tree[cur].r)/2;
    if (ql<=mid)
        ans+=query_interval(cur*2, ql, qr);
    if (qr>mid)
        ans+=query_interval(cur*2+1, ql, qr);
    return ans; 
} 
//区间更新 加值 
void update_interval(int cur, int l, int r, int val){
   
   
    if (l<=tree[cur].l && tree[cur].r<=r){
   
   
        tree[cur].val+=(tree[cur].r-tree[cur].l+1)*val;
        tree[cur].lazy+=val;
        return;
    }
    pushdown(cur);

    int mid=(tree[cur].l+tree[cur].r)/2;
    if (l<=mid)
        update_interval(cur*2, l, r, val);
    if (r>mid)
        update_interval(cur*2+1, l, r, val);

    pushup(cur);
} 
int main(){
   
   

    return 0;
}

参考链接:
https://blog.csdn.net/zhhe0101/article/details/53871453
https://blog.csdn.net/weixin_40788897/article/details/81539106

相关文章
|
监控 NoSQL Redis
如果 Redis 宕机,怎么保证它系统的可用性、持久性、安全性
如果 Redis 宕机,怎么保证它系统的可用性、持久性、安全性
450 0
|
3月前
|
存储 数据挖掘 关系型数据库
更高效的数据处理解决方案:基于 MinIO 部署 Apache Doris 存算分离版本实践
现代数据处理在多维度面临严峻挑战,一方面,数据量的持续增长致使传统存储成本居高不下,非结构化数据所占比例日益攀升,进一步加重了存储负担,且数据质量问题推高了存储和清洗成本;另一方面,企业内部往往存在多套系统,数据难以集成,这对数据分析的成本和时效性也提出了更高的要求。Apache Doris 作为一款具备高性能的实时分析数据库,拥有湖仓一体的能力。当它与 MinIO 这样高性能且 S3 兼容的对象存储系统相结合时,能够构建出一个高效且具备低成本特性的数据分析系统。本文将介绍基于 Apache Doris 和 MinIO 的存算分离部署教程与使用实践。
437 0
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
570 9
|
C++ iOS开发 MacOS
常用的 VSCode 快捷键【大全】,提升你的编码速度
常用的 VSCode 快捷键【大全】,提升你的编码速度
常用的 VSCode 快捷键【大全】,提升你的编码速度
|
JSON JavaScript 数据安全/隐私保护
npm命令:常用npm命令及其详解!
npm命令:常用npm命令及其详解!
|
存储 自然语言处理 NoSQL
深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之列存(二)
深入解析Elasticsearch的内部数据结构和机制:行存储、列存储与倒排索引之列存(二)
|
XML Java 数据库连接
【异常解决】解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)问题
【异常解决】解决org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)问题
579 0
|
Java 编译器 C++
Java同步锁Synchronized底层源码和原理剖析
Java同步锁Synchronized底层源码和原理剖析
273 0
|
Java
【SpringBoot】WebMvcConfigurer实现类不被加载(o.s.web.servlet.PageNotFound : No mapping for GET)的问题解决
【SpringBoot】WebMvcConfigurer实现类不被加载(o.s.web.servlet.PageNotFound : No mapping for GET)的问题解决
1658 0

热门文章

最新文章