RMQ(Range Minimum/Maximum Query)问题是指:对于长度为n的数列A,回答若干询问RMQ(A,i,j),返回数列A中下标i,j里的最小/大值,即RMQ问题是指求区间最值的问题。

时间复杂度:O(N)~ O(logN)

主要思想:分治/倍增/动态规划

主要算法:

1.朴素(暴力搜索)//略过不表

2.线段树

3.ST(Sparse-Table)算法(动态规划)

线段树:线段树能在对数时间logN在数组区间上进行更新与查询。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。

线段树是一种二叉搜索树,与区间树相似,将一个区间划分为一些单元区间,每个单元区间对应线段树中的一个叶节点。对于线段树中的每一个非叶子节点[i,j],定义如下:

第一个节点维护区间[i,j]的信息

if i<j,那么左孩子维护区间[i,(i+j)/2]的信息,右孩子维护区间[(i+j)/2+1,j]的信息。

线段树至少支持下列操作:

insert(t,x):将包含区间int的元素x插入到树t中;

delete(t,x):从线段树t中删除元素x;

search(t,i):返回一个指向树t中元素x的指针。

区间在[1,5]内的线段树 

基本结构:

线段树是建立在线段的基础上,每个结点都代表了一条线段[a , b]。长度为1的线段称为元线段。非元线段都有两个子结点,左结点代表的线段为[a , (a + b ) / 2],右结点代表的线段为[( a + b ) / 2 , b]。

右图就是一棵长度范围为[1 , 5]的线段树。

长度范围为[1 , L] 的一棵线段树的深度为log ( L - 1 ) + 1。这个显然,而且存储一棵线段树的空间复杂度为O(L)。

线段树支持最基本的操作为插入和删除一条线段。下面以插入为例,详细叙述,删除类似。

将一条线段[a , b] 插入到代表线段[l , r]的结点p中,如果p不是元线段,那么令mid=(l+r)/2。如果b<mid,那么将线段[a , b] 也插入到p的左儿子结点中,如果a>mid,那么将线段[a , b] 也插入到p的右儿子结点中。

插入(删除)操作的时间复杂度为O (Log N)。

实际应用:

上面的都是些基本的线段树结构,但只有这些并不能做什么,就好比一个程序有输入没输出,根本没有任何用处。

最简单的应用就是记录线段有否被覆盖,并随时查询当前被覆盖线段的总长度。那么此时可以在结点结构中加入一个变量int count;代表当前结点代表的子树中被覆盖的线段长度和。这样就要在插入(删除)当中维护这个count值,于是当前的覆盖总值就是根节点的count值了。

另外也可以将count换成bool cover;支持查找一个结点或线段是否被覆盖。[1]

实际上,通过在结点上记录不同的数据,线段树还可以完成很多不同的任务。例如,如果每次插入操作是在一条线段上每个位置均加k,而查询操作是计算一条线段上的总和,那么在结点上需要记录的值为sum。

这里会遇到一个问题:为了使所有sum值都保持正确,每一次插入操作可能要更新O(N)个sum值,从而使时间复杂度退化为O(N)。

解决方案是Lazy思想:对整个点进行的操作,先在结点上做标记,而并非真正执行,直到根据查询操作的需要分成两部分。

根据Lazy思想,我们可以在不代表原线段的结点上增加一个值toadd,即为对这个结点,留待以后执行的插入操作k值的总和。对整个结点插入时,只更新sum和toadd值而不向下进行,这样时间复杂度可证明为O(logN)。

对一个toadd值不为0的结点整个进行查询时,直接返回存储在其中的sum值;而若对其一部分进行查询,则要更新其左右子结点的sum值,然后把toadd值传递下去,再对这个查询本身,左右子结点分别递归下去。时间复杂度也是O(logN)。

ST算法:

关于ST算法,实际上它本身并不难,它的思想是动态规划。主要用来求RMQ问题,时间复杂度为O(NlgN+M)

关于RMQ问题描述:

输入N个数和M次询问,每次询问一个区间[L,R],求第L个数到R个数之间的最大值,或者是求最小值。

它的原理阐述如下:

对于一个数组A[0...N-1],我们用f[i][j]表示A[i]到A[i+2^j-1],这个范围内的最大值。

由于此区间的元素个数很明显为2^j个,所以我们又可以从中间平分为两部分,这样每部分又有2^(j-1)个元素,这样我们就知道区间[i,i+2^j-1]可以分为[i,i+2^(j-1)-1]和[i+2^(j-1),i+2^j-1]两部分,我们只需要求出后面两个区间最大值的较大值,就可以知道前面区间的最大值了。

所以到了这里,很明显可以写出状态转移方程:

f[i][j]=max(f[i][j-1],f[i+2^(j-1)][j-1])

当然很明显知道初始化f[i][0]=A[i]

当然上面i,j的范围是多少呢?

现在我们来分析一下:我们已经说了如果用上述原理一个区间的元素是2^j个,而可以知道2^j<=N的,所以这样就得到j<=log(N)/log(2);  当然j还大于等于1

对于i,就直接有i+2^j-1<N就行了。

到了这里,我们就可以把f[i][j]求出来了。

接下来就是query()了。

这个怎么办呢,其实很容易,我们先求出满足条件2^x=R-L+1的最大x

这样我们我们就可以把区间[L,R]求最值问题转化为了求区间[L,L+2^x-1]和区间[R-2^x+1,R]最大值的较大值了,为什么可以这样做,因为这两个区间中间有重叠。

但是这两个区间的并一定等于区间[L,R],所以到了这里ST算法的原理基本常阐述完毕了。

剩下的就是代码实现了。

#include <stdio.h>
#include <math.h>
#define N 1005 int m,n;
int a[N];
int f[N][N]; int max(int a,int b)
{
return a>b? a:b;
} void ST()
{
int i,j;
for(i=;i<n;i++)
f[i][]=a[i];
for(j=;j<=(int)((log((double)n)/log(2.0)));j++)
{
for(i=;i+(<<j)-<n;i++)
f[i][j]=max(f[i][j-],f[i+(<<(j-))][j-]);
}
} int query(int L,int R)
{
int x=(int)(log((double)(R-L+))/log(2.0));
return max(f[L][x],f[R-(<<x)+][x]);
} int main()
{
int i,L,R;
while(~scanf("%d%d",&n,&m))
{
for(i=;i<n;i++)
scanf("%d",&a[i]);
ST();
while(m--)
{
scanf("%d%d",&L,&R);
printf("%d\n",query(L-,R-));
}
}
return ;
}

RMQ问题心得的更多相关文章

  1. RabbitMQ学习之:(一)初识、概念及心得

    因为网上有一篇很好的RMQ的入门帖子http://lostechies.com/derekgreer/tag/rabbitmq/,所以我就不多说了,就说说我目前看了该作者1~5章后,自己的心得.(所以 ...

  2. 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)

    An easy problem A Time Limit: 1000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Pr ...

  3. HDU3183 RMQ/贪心

    A Magic Lamp Problem Description Kiki likes traveling. One day she finds a magic lamp, unfortunately ...

  4. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  5. NoSql数据库使用半年后在设计上面的一些心得

    NoSql数据库这个概念听闻许久了,也陆续看到很多公司和产品都在使用,优缺点似乎都被分析的清清楚楚.但我心里一直存有一个疑惑,它的出现究竟是为了解决什么问题? 这个疑惑非常大,为此我看了很多分析文章, ...

  6. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  7. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  8. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  9. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

随机推荐

  1. BZOJ4597 SHOI2016随机序列(线段树)

    先考虑题目所说的太简单了的问题.注意到只要把加减号相取反,就可以得到一对除了第一项都互相抵消的式子.于是得到答案即为Σf(i)g(i),其中f(i)为前缀积,g(i)为第i个数前面所有符号均填乘号,第 ...

  2. 在iis上部署ssl证书 https

    1.取走证书下载下来的文件.解压iis的压缩包. 2.打开internet信息服务iis管理器 3.双击打开后,选择导入,导入我们刚刚解压得到的pfx文件,这个pfx文件就是你需要部署域名的那个文件. ...

  3. CentOS系统缺少库文件解决办法

    By francis_hao    May 31,2017   程序在编译时出现缺少库文件的提示,如下: as: error while loading shared libraries: libz. ...

  4. [洛谷P2073] 送花

    送花 题目背景 小明准备给小红送一束花,以表达他对小红的爱意.他在花店看中了一些花,准备用它们包成花束. 题目描述 这些花都很漂亮,每朵花有一个美丽值W,价格为C. 小明一开始有一个空的花束,他不断地 ...

  5. Planning your upgrade with Upgrade Advisor

    Planning your upgrade with Upgrade Advisor You should use the Upgrade Advisor tool (if it is availab ...

  6. javascript中arguments的应用——不定项传参求和

    <script type="text/javascript"> window.onload=function(){ function sum(){ var result ...

  7. C++ Review

    #include "iostream" #include "iomanip" #include "cstdio" using namespa ...

  8. Nios II 中的缓存和内存数据的读写

    nios 使用地址中31bit来表示访问是否bypass cache.如果bit 31=0 表示不bypass cache,即使用cache里的数据:如果bit 31=1表示bypass cache, ...

  9. [BZOJ1004] [HNOI2008]Cards解题报告(Burnside引理)

    Description 小春现在很清闲,面对书桌上的N张牌,他决定给每张染色,目前小春只有3种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun很快就给出了答案.进一步,小春要求染出Sr张红 ...

  10. NYOJ 973 天下第一 (最短路)

    题目链接 描述 AC_Grazy一直对江湖羡慕不已,向往着大碗吃肉大碗喝酒的豪情,但是"人在江湖漂,怎能 不挨刀","人在江湖身不由己",如果自己的武功太差,在 ...