线段树

C++ 线段树 线段树基本常识 线段树是一种二叉搜索树(即每个节点最多有两颗子树),与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 如下图,就是一颗 [1,10] 的线段树的分解过程: 由图可得出一个结论,线段树的最大深度不超过,且每一颗线段树需要 4*n 的辅助空间,如果没有开到 4*n ,那就完美 RE 了!!! 线段树的的存储 线段树采用的是堆式储存法,即编号为 k 的节点的做儿子为 k... 阅读详情

树结构的基本思想是分割。普通二叉搜索树是按对象来进行划分,效果往往和数据结构内对象有关;而线段树是根据关键码的可能范围来分的,这种技术叫做关键空间分解!

 

线段树的处理对象是线段(一般意义上的区间可以抽象成线段),它把线段组织成利于检索和统计的形式,本质上是线段的二叉搜索树!当然,线段树特殊点在与其中的线段可以分解和合并,另外,线段树操作的是整个区间,它的渐进时间效率不依赖于数据结构中的对象。

 

线段树是一颗二叉搜索树,最终将一个区间[1, n]划分为一些[i, i+1]的单元区间,每个单元区间对应线段树中的一个叶子节点;每个节点用用变量count来记录覆盖该节点的线段条数。

那么线段树的处理对象是什么呢?答案就是一段较狭窄的区间,区间上的格点对应有限个固定的变量,就像是线性的数组用完全二叉排序树的形式表达。处理问题时,抽象出区间上的格点,也即是明确每个格点对应变量的含义!

 

线段树的定义:

设为T(a, b),参数a和b表示顶点T为区间[a, b]。区间的长度b-a记为L。递归定义T[a, b]如下:

1)当区间长度L>1时,区间[a, (a+b) div 2]为T的左孩子,区间[(a+b) div 2, b]为T的右孩子;

2)如区间长度L=1时,T即为一个叶子顶点,表示区间[a, a+1];

区间[1, 10]的线段树如下:

 

定理:线段树把区间上的任意一条线段都分为不超过2lb(L)条线段。

线段树是平衡树,它的深度为lb(L),能在O(lb(L))的时间内完成一条线段的插入、删除、查找等工作。

 

线段树的节点类型定义如下:

  Type

Lines_Tree = Object

  B, E    :  integer;       {结点表示的区间的顶点标号B, E}

  count  :  integer;       {覆盖这一结点区间的线段数}

  leftchild,  rightchild  :  ↑Lines_Tree;    {二叉树的两个子结点}

end

 

建立线段树:

Procedure  Lines_tree.Build(l, r : integer)

1         B   ß  l            {左端点}

2        E   ß  r            {右端点}

3        count  ß  0        {初始化}

4        If  r - l  >  1       {是否需要生成子结点,若r-l=1则是初等区间}

5          then   k  ß  (l  +  r)       {平均分为两部分}

6                 new(leftchild)

7                 leftchild↑.Build(l, k)    {建立左子树}

8                 new(rightchild)

9                 rightchild↑.Build(k, r)   {建立右子树}

10       else   leftchild  ß  nil

11              rightchild  ß  nil

 

将区间[l, r]插入线段树:

设线段树的根编号为v,如果[l, r]完全覆盖了v顶点代表的区间[a, b],那么显然该顶点上的基数(即覆盖线段树)加1;否则,如果[l, r ]不跨越区间中点,就只对左树或者右树上进行插入。如果[l, r]跨越区间中点,则在左树和右树上都要进行插入。注意观察插入的路径,一条待插入区间在某一个顶点上进行“跨越”,此后两棵子树上都要向下插入。

Procedure  Lines_Tree.Insert(l,r  :  integer) 

{[l,  r ]是待插入区间,l、r都是原始顶点坐标}

1         if  (l  <=  a[B])  and   (a[E]  <=  r)               

2          then  count  ß  count  +  1            {盖满整个结点区间}

3          else  if  l < a[(B  +  E) div  2]  {是否能覆盖到左孩子结点区间}

4                  then  leftchild↑.Insert(l, r)      {向左孩子插入}

5               if  r > a[(B  +  E) div  2 ]   {是否能覆盖到右孩子结点区间}

6                  then  rightchild↑.Insert(l,  r)     {向右孩子插入}

 

将区间[l, r]从线段树中删除:

从线段树中删除一个区间的方法与插入几乎完全类似。

Procedure  Lines_Tree.Delete(l, r  :  integer)

{[l,  r]是待删除区间,l、r都是原始顶点坐标}

1         if  (l  <=  a[B])  and   (a[E]  <=  r)

2          then  count  ß  count  -  1            {盖满整个结点区间}

3          else  if  l < a[(B  +  E)  div  2 ] {是否能覆盖到左孩子结点区间}

4                  then  leftchild↑.Delete(l,  r)      {向左孩子删除}

5               if  r > a[(B  +  E)  div  2 ] {是否能覆盖到右孩子结点区间}

6                  then  rightchild↑.Delete(l, r)     {向右孩子删除}

特别注意:执行Lines_Tree.Delete(l, r : integer) 的先决条件是区间[l, r]曾被插入且还未删除。如果建树后插入区间[2,5]而删除区间[3,4]是非法的。

 

线段树的动态维护:

线段树的作用主要体现在可以方便地动态维护其某些特征。例如,增加一个数据域Lines_Tree.M,存储以该结点为根的子树上线段并集的长度(即测度):

 

         a[E] - a[B]   该结点Count>0

M  =    0          该结点为叶结点且Count=0

         Leftchild↑.M + Rightchild↑.M  该结点为内部结点且Count=0

 

只要每次插入或删除线段区间时,更新已访问顶点的M值,就可以在插入和删除的同时维持好M。求整个线段树的并集长度时,只要访问M[ROOT]的值就行了。

据此,可以用Lines_Tree.Update来动态地维护Lines_Tree.M。Update在每一次执行Insert或Delete之后执行。定义如下:

 

Procedure  Lines_Tree.Update

1         if  count  >  0

2          then  M  ß  a[E] - a[B]     {盖满区间,测度为a[j] – a[i]}

3          else  if  E  -  B  =  1         {是否叶结点}

4                  then  M  ß  0       {该结点是叶结点}

5                  else  M  ß  Leftchild↑.M  +  Rightchild↑.M
                                           {
内部结点}

Update的复杂度为O(1),则用Update来动态维护测度后执行根结点的Insert与Delete的复杂度仍为O(logN)。

 

连续段数:(区间中互不相交的线段条数)

这里的连续段数指的是区间的并可以分解为多少个独立的区间。如[1,2]∪[2,3]∪[5,6]可以分解为两个区间[1,3]与[5,6],则连续段数为2。增加一个数据域Lines_Tree.line表示该结点的连续段数。Line的讨论比较复杂,内部结点不能简单地将左右孩子的Line相加。所以再增加Lines_Tree.lbd与Lines_Tree.rbd域。定义如下:

 

                1    左端点I被描述区间盖到

lbd  = 

                0    左端点I不被描述区间盖到


 

                1     右端点J被描述区间盖到

rbd  = 

                0     右端点J不被描述区间盖到

 

lbd与rbd的实现:

 

               1  该结点count > 0;

 

lbd  =   0  该结点是叶结点且count = 0;

 

               leftchild↑.lbd    该结点是内部结点且count=0。

 

 

               1  该结点count > 0;

 

rbd  =   0  该结点是叶结点且count = 0;

 

               rightchild↑.rbd   该结点是内部结点且count=0。

 

 

有了lbd与rbd,Line域就可以定义了:


                 1  该结点count > 0;

 

Line =      0  该结点是叶结点且count = 0;

 

                Leftchild↑.Line  +  Rightchild↑.Line  -  1
               
当该结点是内部结点且Count=0,Leftchild↑.rbd = 1且Rightchild↑.lbd = 1;

 

                Leftchild↑.Line  +  Rightchild↑.Line  
               
当该结点是内部结点且Count=0,Leftchild↑.rbd与Rightchild↑.lbd不都为1。

 

据此,可以定义Update’动态地维护Line域。与Update相似,Update’也在每一次执行Insert或Delete后执行。定义如下:

Procedure  Lines_Tree.Update’

1         if  count  >  0           {是否盖满结点表示的区间}

2          then  lbd   ß  1

3               rbd   ß  1

4               Line  ß  1

5          else  if   E  -  B  =  1     {是否为叶结点}

6                  then  lbd   ß  0   {进行到这一步,如果为叶结点,
                                                count = 0}

7                        rbd  ß  0

8                        line  ß  0

9                  else  line  ß   Leftchild↑.line  +  Rightchild↑.line  - 

                              Leftchild↑.rbd * Rightchild↑.lbd

{用乘法确定Leftchild↑.rbd与Rightchild↑.lbd是否同时为1}

 

至此,线段树构造完毕,完整的线段树定义如下:

 

Lines_Tree = object

  i, j     :  integer;

  count   :  integer;

  line     :  integer;

  lbd, rbd  :  byte;

  m       :  integer;

  leftchild,

  rightchild  :  ↑Lines_tree;

  procedure  Build(l, r : integer);

  procedure  Insert(l, r : integer);

  procedure  Delete(l, r : integer);

  procedure  Update;

  procedure  Update’;

end

 

 

 

线段树详解(包含加法线段树、乘法线段树及区间根号线段树,简单易懂) 线段树及简单应用。 阅读详情

相关推荐

线段树合并与线段树分裂

线段树合并是指建立一棵新的线段树,这棵线段树的每个节点都是两棵原线段树对应节点合并后的结果。线段树分裂实质上是线段树合并的逆过程。线段树分裂只适用于有序的序列,无序的序列是没有意义的,常用在动态开点的权值线段树。线段树分裂与线段树合并密不可分,一般来说没有只分裂不合并的题。的救灾粮,问所有操作结束后每个节点类型最多的救灾粮是那种。一棵树,点有点权,问每个节点的子树内有多少节点点权比它大。从这棵树的根节点开始递归分裂,当节点不存在时,递归结束。显然,对于两颗满的线段树,合并操作的复杂度是。

conti123的博客 934

【学习笔记】详解线段树(浅显易懂,匠心之作,图文并茂)

超详解线段树(浅显易懂,几乎涵盖所有线段树类型讲解,匠心之作,图文并茂)

weq2011的博客 3万+

二维线段树(线段树套线段树)

由于网上的其它博客对初学者非常不友好,所以我就来写一篇博客帮助萌新们快速入门树套树啦。所谓线段树套线段树就是在第一棵线段树的每一个结点上再开一颗线段树,第一棵线段树用来维护第一维的数据,再用第一棵线段树上新开的线段树来维护第二维的数据。是不是没听懂呢,下面我们直接上图: 这就是树套树大概的模样,横线上面是第一棵线段树,下面是对第一棵线段树的每一个结点新开的线段树,就像是每一个点内都套着一棵线段树一样,那么二维线段树就可以用来维护平面信息下面看一道例题: 陌上花开 首先对第一维进行排序,然后用树套树进行处理

NEUQ_snowy的博客 4432

数据结构之线段树

文章目录线段树(区间树)Segment Tree线段树的概念为什么要使用线段树手写一个线段树线段树中的区间查询线段树问题 LeetCode303LeetCode307对区间进行操作的时间复杂度 线段树(区间树)Segment Tree 线段树的概念 线段树是一种特殊的树结构。这种数据结构主要用于解决“线段”或者是“区间”这种特殊的数据 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些...

qq_24095055的博客 1228

手把手教你用S7-PLCSIM Advanced V3.0搭建PLC仿真测试环境(含WinPcap避坑指南)

本文详细介绍了如何使用西门子S7-PLCSIM Advanced V3.0搭建PLC仿真测试环境,包括WinPcap 4.1.3驱动的安装避坑指南。从环境准备、软件安装到配置调试,提供了一套完整的解决方案,帮助工程师和教学人员快速构建可靠的PLC仿真环境,解决常见的报错问题。

weixin_30879169的博客 641

实战指南(一)SCAPS-1D太阳能电池模拟软件从零到一:模型构建与参数解析

本文详细介绍了SCAPS-1D太阳能电池模拟软件的使用方法,从模型构建到参数解析,帮助用户快速掌握这一免费且功能强大的工具。特别适合用于单结/多结电池的电学性能分析,涵盖钙钛矿电池等常见结构的模拟实践,并提供参数调试和收敛性问题处理的实用技巧。

weixin_30588675的博客 445

【数据结构】线段树

本文介绍了线段树的相关知识。

代码星辰的博客 933

MS1861宏晶微视频显示与控制器芯片:开发资料全解析与应用指南

本文全面解析了宏晶微MS1861视频显示与控制器芯片的核心功能与开发流程。该芯片作为高性能的“视频信号翻译官”,支持HDMI、LVDS等多种输入与MIPI、LVDS等输出,集成强大的图像处理与OSD叠加功能。文章详细介绍了从资料获取、环境搭建到以HDMI转MIPI为例的实战配置与调试技巧,为工业HMI、广告机等应用的开发者提供了完整的应用指南。

weixin_29198045的博客 337

线段树介绍

文章目录 1 线段树介绍 1.1 线段树的结构及性质 1.2 建树 2 区间查询 3 单点更新 4 区间更新 5 线段树的优缺点 后记 1 线段树介绍   线段树,我刚开始听到这个名字的时候,感觉就是高大上,怕难度会很大,但是实际学起来的时候,会发现还是挺好理解的,很亲民→_→   扯远了,先盗个图抛个问题:   图中的RMQ指的是(Range Minimum Query)问题(区间最值查询)。按暴力法直接一个for循环过去查询,每次查询的时间复杂度为O(N),频繁查询就是O(MN)了,性能上肯定要爆

木牛的博客 691

【CIC-IDS数据集+机器学习】实现网络流量异常检测

本项目基于CIC-IDS数据集,使用多种机器学习算法实现网络流量异常检测系统。项目采用了完整的机器学习工作流程,从数据预处理到模型部署,实现了高精度的网络入侵检测。

XiaoMu_001的博客 1935

Microsoft Bitlocker企业级管理部署方案

BitLocker是Windows 10以及更高版本中内置的磁盘加密工具,是一种可靠的数据保护机制,可以保护计算机上的敏感数据不被未经授权的人访问。BitLocker的工作原理是将整个系统卷或其他数据卷加密的同时,向某个可信软件或硬件模块请求密钥解密数据。BitLocker最大的好处在于其内置于Windows系统,所以用户无需安装其他软件或购买额外的许可证或硬件设备。本文将介绍Microsoft BitLocker企业级管理部署方案,包括:BitLocker部署前的准备工作。

xueyunshengling的博客 2073

【算法】— 线段树详解

线段树:一种用于区间处理的数据结构,基于二叉树,也就是对于一个线段,我们会用一个二叉树来表示,首先,将每一个数字放在二叉树的叶子结点上,从叶子结点开始,两两合并为一棵子树,将包含的两个叶子结点的最小值存入该子树的父结点

DAY I 的成长之路 1439

8 卡 GPU 服务器与 NVLink/NVSwitch 互联技术

NVLink 是一种点对点的高速互连技术,单条 NVLink 就是一条全双工双路信道,每条 NVLink 链路可以将 2 个 GPU 直连起来,并且每个 GPU 可以提供多条 NVLink 接口连接多个 GPU。另外,PCIe Switch 互联拓扑中的 GPU 之间可能存在 GPU0→Switch0→CPU0→CPU1→Switch1→GPU7 的通信链路,它的通信不可避免的存在一定的延迟,因而更适合用于对信号效率不敏感且追求性价比的使用场景,如:推理、云计算等领域。本文讨论的是单机 GPU 卡间互联。

烟云的计算 4262

【算法】线段树

几乎是算法竞赛最常用的数据结构了,它主要用于(要求满足结合律)。与树状数组相比,它可以实现的,还可以同时(加、乘),更具通用性。如题,已知一个数列,你需要进行下面两种操作:1.将某区间每一个数加上x2.求出某区间每一个数的和第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

weixin_73366312的博客 1808

用urdf给自己的ROS小车编写模型

3.3 使用urdf编写自己的ROS小车模型 3.3.1 常见的ROS小车结构有哪些? 下面就是常见的ROS小车,相信在大家的脑海里已经有了自己小车的样子,下面我和大家一起使用urdf对ros小车建模。 这里只对urdf进行简单介绍,然后就带大家使用urdf最基础的标签,建立机器人的urdf机器人模型。关于更多细节,请参看官网:http://wiki.ros.org/urdf/Tutorials 3.3.2 什么是urdf?建模的原因? 什么是urdf? URDF(Unified Robot Descri

「小白学移动机器人」一个专注分享移动机器人相关知识的公众号! 1万+

极验点选click3.1.0所对应fullpage.js的逆向分析

极验3代点选验证,本文适用于使用click.3.1.0.js和fullpage919-eyz9lh.js版本的web验证码,没有细节内容,适合有基础的开发者阅读。

shanf7921的博客 648

【线段树】线段树入门之入门

线段树的入门级 总结       线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。       对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树,最后的子节点数目为N,即整个线段区间的长度。       使用线段树可以

生命有一种绝对 4万+

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

线段树详解

1. 什么是线段树 顾名思义 , 线段树是一棵二叉树 , 但不同的是这棵树的结点储存的值是一个数列中 [l,r][l,r][l,r] 的某个需要的值 (例如,求和,求最大值,求最小值) 这是一棵典型的线段树 ,其性质是 : 若其中一子节点编号为 aaa , 则该节点左儿子编号为 2a2a2a , 其右儿子编号为 2a+12a+12a+1 2. 线段树的用处 线段树的用处就是,对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log2n)O(log_2 n)O(log2​n). 3.

orz 1万+

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

【线段树模板以及Codeforces线段树专题总结】

线段树模板 //线段树一般用来解决可合并的区间问题 //树上维护子树区间的问题也可以通过dfs序+线段树去维护 //不要忘记build,dfs序问题build时注意下标 //数组记得开4倍,push_down一定要想好顺序 //对于每个问题,我们只要考虑清楚push_down和push_up的写法即可 //当问题不好处理的时候,想象一下对于单次询问暴力的做法,再进行区间操作 struct T { ...

lajiyuan的博客 4090

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

线段树及线段树模板

线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为Olog⁡NO(\log N)OlogN。而未优化的空间复杂度为2N2N2N,实际应用时一般还要开空间为4N4N4N的数组以免越界,因此有时需要离散化让空间压缩。线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。

AllenAC的博客 1234

有关线段树合并

目录:一:线段树合并概念二:线段树合并应用。

2509_93020071的博客 2195

线段树合并

文章目录前置芝士线段树合并概念merge题目描述输入格式输出格式代码 前置芝士 权值线段树 动态开点线段树 线段树合并的全称为动态开点权值线段树合并 加个链接 线段树合并 概念 顾名思义,就是建立一棵新的线段树保存原有的两颗线段树的信息。 merge 线段树合并所完成的操作就是:在相同区间内,对应位置相加。 合并方式主要如下:两个相同区间的节点 p{p}p 和 q{q}q,合并区间 [l,r]{[l,r]}[l,r]。 若 p{p}p 和 q{q}q 有一者为 0{0}0,则另一者为根。 若 l=

Cauchy的博客 4223

详解线段树

但是在做题的时候还是会对模板进行修改,修改的点主要在区间val的意义上,我们这里模板里面val代表的是区间和,但后面题目里面可能是 区间最大值 、区间最小值…,但是万变不离其宗,线段树的结构是不会变的。

潜心钻研技术 1353

线段树之zkw

线段树之zkw,主要的作用是用来卡常,虽然平时的使用似乎不太多,但是可以学习一下。

月巴虫丰博客 2989
上一篇: 桶排序及其应用
下一篇: 《认清C++语言》之--内存管理
ACE1985
博客等级 码龄17年 1307粉丝 308原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值