线段树简介

news/2024/10/28 21:19:32/

1、线段树是什么?

线段树(Segment Tree)是一种经典的数据结构,它是一颗二叉树,每个节点都代表区间。线段树用于解决静态区间问题和动态区间问题。

它的主要思想是将区间划分成若干个小区间,每个节点代表一个小区间。每个节点的值都是该区间内所有元素的某个函数(如和、最大值、最小值等)的值。在线段树中,每个节点有两个儿子,分别代表该节点所表示区间的左半部分和右半部分。这种表示方法可以在O(logN)的时间内完成区间操作,所以非常适合处理区间问题。

2、如何建立线段树?

对于一个给定的区间[left, right],如果该区间不是叶节点,则将该区间划分为两个区间[mid + 1, right]和[left, mid]。若该区间为叶节点,则将该节点的值赋为该区间的元素值。

void build(int l,int r, int rt){//建立线段树,【l,r】 是当前区间 if(l==r){Sum[rt]=A[l];return;}int m=(l+r)>>1;build(l,m,rt<<1);build(m+1,r,rt<<1|1);pushup(rt);//更新节点信息 
} 

2.1 如何查询区间操作?

考虑查询区间[begin, end]的和。首先将该区间[left, right]不断地分成两个子区间,直到区间[left, right]完全被包含于[begin, end]内。然后计算该区间内元素的和。

void PushDown(int rt,int ln,int rn){//ln,rn为左子树,右子树的数字数量。 if(Add[rt]){//下推标记 Add[rt<<1]+=Add[rt];Add[rt<<1|1]+=Add[rt];//修改子节点的Sum使之与对应的Add相对应 Sum[rt<<1]+=Add[rt]*ln;Sum[rt<<1|1]+=Add[rt]*rn;//清除本节点标记 Add[rt]=0;}
}int query(int L,int R,int l,int r,int rt){if(L<=l&&r<=R){return Sum[rt];}int m=(l+r)>>1;//下推标记,否则Sum可能不正确PushDown(rt,m-l+1,r-m); int ans=0;if(L<=m)//左子区间与[L,R]有重叠,递归 ans+=query(L,R,l,m,rt<<1);if(R>m)//右子区间与[L,R]有重叠,递归 ans+=query(L,R,m+1,r,rt<<1|1);return ans;
}

2.2 如何更新区间元素?

假设要将区间中第i个元素的值更新为v。首先找到线段树中对应节点,更新节点的值,并递归向上更新所有祖先节点的值。

void update(int num,int c,int l,int r,int rt){//【l,r】 是当前区间,点修改 if(l==r){Sum[rt]+=c;return;}int m=(l+r)>>1;if(num<=m)update(num,c,l,m,rt<<1);else update(num,c,m+1,r,rt<<1|1);pushup(rt);//更新了子节点之后,本节点也要更新 
} 

接下来,我们通过一个简单的例子来更加深刻地理解线段树的思想。

3、例子

题目描述:给定一个长度为N的序列,支持两种操作:将区间[left, right]中的每个元素加上v,并查询区间[begin, end]的和。

Solution:

建立线段树

因为序列的长度为N,所以形成的线段树的叶节点个数应该为N。因此,在线段树的构造过程中,每个节点要么是叶节点,要么至少有一个儿子。所以,表示线段树的数组的长度应该是4*N。

void buildST(int p, int left, int right) { if (left == right) { //如果该区间为叶节点 ST[p] = A[left]; return; } int mid = (left + right) / 2; buildST(p * 2, left, mid); //建立左子树 buildST(p * 2 + 1, mid + 1, right); //建立右子树 ST[p] = ST[p * 2] + ST[p * 2 + 1]; //计算该节点的值 
}

由于ST[p]代表区间[left, right]的和,ST[p * 2]代表区间[left, mid]的和,ST[p * 2 + 1]代表区间[mid + 1, right]的和,因此,ST[p]的值可以直接从ST[p * 2]和ST[p * 2 + 1]的值计算得来,即ST[p] = ST[p * 2] + ST[p * 2 + 1]。

查询区间操作

void queryST(int p, int left, int right, int begin, int end) { if (begin <= left and end >= right) { //如果该区间[left, right]被包含于[begin, end]内         ans += ST[p]; //计算该区间的和 return; } int mid = (left + right) / 2; if (begin <= mid) { queryST(p * 2, left, mid, begin, end); //查询左子树 } if (end > mid) { queryST(p * 2 + 1, mid + 1, right, begin, end); //查询右子树 } 
}

更新区间元素

void updateST(int p, int left, int right, int index, int value) { if (left == right) { //找到线段树中对应节点 ST[p] += value; //更新该节点的值 return; } int mid = (left + right) / 2; if (index <= mid) { updateST(p * 2, left, mid, index, value); //更新左子树 } else { updateST(p * 2 + 1, mid + 1, right, index, value); //更新右子树 } ST[p] = ST[p * 2] + ST[p * 2 + 1]; //递归向上更新该节点的祖先节点的值 
}

至此,我们可以轻松地解决这个问题了。

4、线段树的应用场景:

  1. 区间查询:例如查询一个区间内的最大值、最小值、区间和等等。

  2. 区间修改:当需要修改一个区间中的某些数值时,线段树可以提供高效的修改操作。

  3. 区间合并:某些问题需要将多个区间进行合并,如区间覆盖或区间合并等问题。

  4. 高效排序:线段树可以帮助我们快速地对一个区间内的数值进行排序。


http://www.ppmy.cn/news/37957.html

相关文章

Leveldb源码解读------Memtable(跳表)详解

在leveldb中的memtable实际上是对核心数据结构skipList做了一个包装&#xff0c;并对外提供了接口。 使用让我们一起来研究一下跳表 为什么使用跳表 因为memtable为了更快的查询&#xff0c;是一个sortmap要求。一般会采用红黑树&#xff0c;不过LevelDB采用的是Skiplist。S…

30行python代码就可以调用ChatGPT API总结论文的主要内容

阅读论文可以说是我们的日常工作之一&#xff0c;论文的数量太多&#xff0c;我们如何快速阅读归纳呢&#xff1f;自从ChatGPT出现以后&#xff0c;有很多阅读论文的服务可以使用。其实使用ChatGPT API非常简单&#xff0c;我们只用30行python代码就可以在本地搭建一个自己的应…

VUE 跳转链接去掉中间#号

问题原因&#xff1a; Vue 的 router 默认是 hash 模式&#xff0c;在 hash 模式下&#xff0c;是会有#号在URL上&#xff1b; 例如如你访问&#xff1a; https://www.baidu.com&#xff0c;实际跳转 https://www.baidu.com/#/index 即它在路由时&#xff0c;在每个路径前面…

《安富莱嵌入式周报》第306期:开源独轮车,Cortex-M85修订版r1发布,Terathon图形数学库,不断变革的IDE开发环境,各个厂家总动员

往期周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1TT411Y7fq 《安富莱嵌入式周报》第306期&#xff1a;开源…

陈刚:大管家健康产业有限公司的联合创始人兼CEO

与其被创业者坑&#xff0c;还不如自己“坑”自己&#xff0c;看投资人为何成为操刀者&#xff01; 想找人来投资自己的项目&#xff01; 那你知道什么样的人才最容易拿到投资吗&#xff1f; 想要在现有的发展状态下有些新的尝试&#xff01; 那你如何稳抓良机&#xff0c;成功…

echarts——实现中国地图+世界地图的切换——技能提升

之前写过一篇文章&#xff0c;是关于中国地图的展示。 vueecharts.js 实现中国地图——根据数值表示省份的深浅——技能提升&#xff1a;http://t.csdn.cn/rfQGl 最后实现的效果如下图所示&#xff1a; 今天遇到一个需求&#xff0c;就是实现中国地图和世界地图的切换。 话不…

客户至上:减少客户服务等待时间的 4 个技巧

在提供出色的客户服务方面&#xff0c;等待时间至关重要。如果客户等待数小时才能得到回复&#xff0c;他们可能会放弃对话甚至可能决定将转向您的竞争对手。 如果您的客户无法处理等待&#xff0c;他们可能会将不满发泄到您的座席身上&#xff0c;这也不利于客服成员的工作。那…

IDEA vs Eclipse:使用体验对比

1. 概述 IDEA 和 Eclipse 都是常见的集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于编写和调试代码。它们都有一些共同的功能&#xff0c;例如代码编辑器、调试器、版本控制等等。但是在具体的使用体验上&#xff0c;它们有很多不同之处。 本文将对 IDEA 和 Eclip…