线段树+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. 【Linux】新建用户 用户组

      案例 hadoop #添加用户组 sudo useradd -s /bin/bash -g hadoop -d /home/hadoop -m hadoop #添加用户 sudo passwd h ...

  2. LAMP环境的搭建(三)----PHP7的安装

    centos自带的PHP源是5.4版本的.如果需要安装PHP 5.4 直接输入 yum install php -y 即可 因为PHP7性能巨大的提升,因此本文选择安装PHP7 如果已经安装过了php ...

  3. mysql 时间戳格式化函数FROM_UNIXTIME和UNIX_TIMESTAMP函数的使用说明

    我们一般使用字段类型int(11)时间戳来保存时间,这样方便查询时提高效率.但这样有个缺点,显示的时间戳,很难知道真实日期时间. MySQL提供了一个时间戳格式化函数from_unixtime来转换格 ...

  4. Struts2流程分析与工具配置

    1. 运行流程 请求 -- StrutsPrepareAndExecuteFilter 核心控制器 -– Interceptors 拦截器(实现代码功能 ) -– Action 的execuute - ...

  5. 海外 App 的推送服务,试试 FCM 吧!!!

    > **版权声明:** > > **本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有.** > > **每周会统一更新到这里,如果喜欢,可关注公 ...

  6. shell之算数运算符、逻辑运算符、关系运算符、布尔运算符、文件测试运算符

    注意事项: (1)bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用: (2)完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Es ...

  7. thinkjs 文件上传

    采用thinkjs框架写前后端 let formdata = new FormData($('form')[0]); $('#fileUpload').submit(function (e) { e. ...

  8. node.js后台快速搭建在阿里云(二)(pm2和nginx篇)

    前期准备 阿里云服务器 node.js pm2 express nginx linux(推荐教程:鸟哥的私房菜) 简介 嗯……我只是个前端而已 在第一部分说完了express篇. 后面继续项目的部署, ...

  9. 使用javaconfig配置freemarker

    package com.yy.config; import org.springframework.context.annotation.Bean; import org.springframewor ...

  10. POI实现excel各种验证和导入的思路总结

      制定标准 导入总是与导出相辅相成的,无规矩不成方圆.所谓的标准都是大家一同来维护和遵守的,那么首先就是制定一个模板. 这样可以减少验证的工作量. 例如时间的规范[yyyy-MM-dd],获取单元格 ...