线段树+RMQ问题第二弹

上篇文章讲到了基于Sparse Table 解决 RMQ 问题,不知道大家还有没有印象,今天我们会从线段树的方法对 RMQ 问题再一次讨论。

正式介绍今天解决 RMQ 问题的方法之前,我先对 RMQ 问题的概念再一次进行说明。RMQ (Range Minimum/Maximum Query ):中文名为“区间最值查询”。RMQ 问题指的是给定一段区间,针对给定区间进行若干次查询,每次给出不同的待查询子区间范围,要求返回子区间内的最大值或者最小值。

RMQ 问题可以看作是线段树的一个应用,本来今天的主角是 RMQ 问题,但我思前想后觉得草草解释线段树或者只展示RMQ一个方面的应用留个小尾巴有点意犹未尽,之前没有接触过线段树的朋友也会觉得云里雾里,因此我改变主意决定以线段树的基本概念和应用作为今天的主要内容,RMQ问题的解决作为整篇文章的一个实例,下面就要进入主题了。

线段树是什么?线段树是一种完美的树,这种树对于处理区间问题有相当高的效率。线段树满足这样一些特点:

一、是一棵完全二叉树,除最后一层之外其余各层均是满的,所有的叶节点均排布在最后一层,所有的节点不是叶节点就是拥有两棵子树的节点。

二、每个节点维护一段区间,其中根节点维护的是整个区间,其余节点均维护的是直接父节点的二分之一区间,也就意味着将父节点维护的区间二等分分别分给左右两个孩子维护。

三、根据节点维护的数据不同,线段树可以实现不同的功能。

四、并非所有的区间问题都可以用线段树来解决。

这样不形象的用文字描述就想让没接触过的人了解线段树实在有点强人所难,我还是画一张丑图来说明一下吧。如下图所示:

以求 RMQ 问题为例我们来深入了解一下有关线段树的性质,假设本篇文章我们的要求是求区间最小值。

由上图可知,该图中的线段树维护的是 n = 8 的区间的数据,每个节点存储的是所维护区间内的最小值,该线段树的深度为 L 。通常情况下整个线段树各节点的值会存储在数组里边,因此我们需要知道线段树的节点数。假设 区间的元素个数为 n ,线段树的深度为 L ,线段树的节点数为 m 。

由上图可知三者满足的关系为:

L = log n +1(对数以 2 为底);即 2^(L-1) = n

m = 2^0 + 2^1 + 2^2 + 2^3 + ......+ 2^( L - 1)

m =( 2^0 + 2^0 )+ 2^1 + 2^2 + 2^3 +...... + 2^( L-1) -1

m = (2^1 + 2^1) + 2^2 + 2^3 +......+ 2^(L-1) - 1

... ...

m = 2^(L-1) + 2^(L-1) -1

m = n + n -1

m = 2n-1

由上面的推导过程可以知道,m = 2n-1是妥妥的。没求证之前,可能很多人看到线段树的图之后,都会觉得规模应该是 O(n log n),虽然不知道这种错觉的理由是什么,但是知道了一点,以后凡事都需要自己亲自验证一番才能彻底打消错误的念头。这也就意味着对线段树的初始化是O(n)的时间复杂度。

现在我们来看一下求区间最值具体是怎样实现的。首先我们知道线段树上存储的是一些固定区间的最值,因此我们要求一些自定义区间的最值时,需要同时结合线段树上的若干个连续区间的多个最值,在其中选择最小的作为最后的结果,由于将整个区间分成若干子区间分别求最值最后合并结果的方法对最后结果的正确性没有影响,因此存在实现上的可行性。那么对于自定义的一个区间,在线段树上具体需要选取哪些区间呢?我们需要选取的是能够完全被自定义区间覆盖的那些区间。对于线段树上的任何一个区间,可能执行的操作有三个:

若该区间中的所有元素均包含在自定义区间中,那么直接返回线段树上存储的该区间最值。

若该区间的所有元素中任何一个元素都不曾出现在自定义区间中,那么自定义区间的最值一定不会来自该区间,这时候返回一个不影响结果判断的值即可。

若该区间既不能被自定义区间完全包含,又存在若干元素包含在自定义区间中,那么递归的对该区间对应的两个子区间分别执行这三个判断。

大概思路就是如此。

虽然将普通区间改造为线段树来维护没有增加过多的任务量,由上面的分析可以知道这么做的效果却是很惊人的,因为利用线段树求区间最值的时候,在树的每一层至多需要访问两个节点,由上至下共 L = log n +1层,也就意味着,找到一个区间的最值需要访问的节点数 至多都不会超过 2 * L - 1 ,因此查找一次区间最值时间复杂度稳定在 O( log n)的时间复杂度,这可是个惊人的发现呢。

线段树的另一个比较有名的应用就是修改区间上某一位置的值,可以从线段树的最底层开始修改,由于在任何一层每个元素只可能出现在一个区间,因此修改一个值的时间复杂度恒为O(log n)。

线段树的两个比较常见的应用都在这里,理论描述上面已经给出,接下来我将核心代码部分附上供大家对细节进行推敲。图片看不清楚的朋友可打开网页http://paste.ubuntu.com/25418076/查看网页版的代码。

今天的分享就到这里,有朋友发现文章中写的不合适的地方可以直接在下方留言区留言纠正。

没有关注公众号的朋友,可以识别下方二维码关注我。


线段树+RMQ问题第二弹的更多相关文章

  1. HDU 1754 I Hate It 线段树RMQ

    I Hate It Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=175 ...

  2. 《白书》上线段树RMQ的实现

    白书上的线段树RMQ实现,自己重写了一遍: #include <bits/stdc++.h> using namespace std; const int MAXN=1<<17 ...

  3. ACM学习历程—HDU 5289 Assignment(线段树 || RMQ || 单调队列)

    Problem Description Tom owns a company and he is the boss. There are n staffs which are numbered fro ...

  4. UVA 11235 Frequent values 线段树/RMQ

    vjudge 上题目链接:UVA 11235 *******************************************************大白书上解释**************** ...

  5. dutacm.club_1094_等差区间_(线段树)(RMQ算法)

    1094: 等差区间 Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)Total ...

  6. Hlg 1832 【线段树 && RMQ】.cpp

    题意: 在给出的区间内求出最大买进卖出的差价. 思路: 对于弱数据:维护一个从左到右的最大差价和最小值.即当发现当前值比最小值小的时候更新最小值,否则看一下当前值与之前最小值的差价是否比最大差价大,是 ...

  7. 单点更新线段树 RMQ

    D. Xenia and Bit Operations time limit per test 2 seconds memory limit per test 256 megabytes input ...

  8. CSU 1809 - Parenthesis - [前缀和+维护区间最小值][线段树/RMQ]

    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809 Bobo has a balanced parenthesis sequenc ...

  9. PKU 2823 Sliding Window(线段树||RMQ||单调队列)

    题目大意:原题链接(定长区间求最值) 给定长为n的数组,求出每k个数之间的最小/大值. 解法一:线段树 segtree节点存储区间的最小/大值 Query_min(int p,int l,int r, ...

随机推荐

  1. My Favorite Color

    我喜欢的颜色收藏.. <H4>标签的颜色: Html中行内样式的设置.. Html中行内样式的设置.. Html中行内样式的设置.. Html中行内样式的设置.. <html> ...

  2. Java获取Object属性值

    做了一个拦截参数的需求,需要获取普通参数和对象参数 参数是Object类型,Object[] paramValues = pjp.getArgs(); 1.获取普通参数 ;i<paramValu ...

  3. Redis持久化总结

    Redis持久化总结 因为Redis是内存型数据库,所以为了防止因为系统崩溃等原因导致数据丢失的问题,Redis提供了两种不同的持久化方法来将数据存储在硬盘里面,一种方法是快照(RDB),它可以将存在 ...

  4. MSF初体验 - kali linux 入侵XP系统

    最近做某安全竞赛平台的比赛,真正开始接触Metasploit这一渗透神器,同时也是装逼神器(2333-.),下面记录一下初步使用Metasploit的过程.首先在百度百科摘录了一段关于Metasplo ...

  5. Struts:文件上传下载

  6. Python学习笔记4

    根据文件类型选择文件 文件 s s.split('.')[1] 即为文件后缀名,据此判断 输出执行后结果到指定文件 os.system('E:\\Learning\\python\\test_case ...

  7. appium python api收集

    1.contexts contexts(self): Returns the contexts within the current session. 返回当前会话中的上下文,使用后可以识别H5页面的 ...

  8. xcode模拟器不显示键盘解决方案

    当我们使用Xcode进行开发的时候,并不是所有的时候都需要将代码运行在iPhone,有时候模拟器就可以解决这些问题, 但是当你使用模拟器的时候会发现,在TextFiled中输入信息时,如果你是用模拟器 ...

  9. 【打死树莓派】-树莓派3代jessie+Opencv-解决安装不了libgtk2.0-dev包问题

    按照国际法先贴问题 Some packages could not be installed. This may mean that you have requested an impossible ...

  10. Nhibernate学习教程(1)-- 开篇有益

    NHibernate之旅(1):开篇有益 本节内容 NHibernate是什么 NHibernate的架构 NHibernate资源 欢迎加入NHibernate中文社区 作者注:2009-11-06 ...