RMQ (Range Minimum/Maximum Query)问题是指:

对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,RMQ问题是指求区间最值的问题。

for循环遍历一边,然后输出,那么你很容易想到会被T飞掉;

1、先写一种比较高效的ST算法解决这个问题。

线段树预处理O(nlogn),查询O(logn),支持在线修改 
ST表预处理O(nlogn),查询O(1),但不支持在线修改

其实ST表是一种动态规划的思想;每次运用倍增思想求解每一个区间;

一个序列的子区间有o(n^2)个,根据倍增思想,我们首先在这个规模中选择一些2的正实数次幂作为代表值;

定义:f(i,j)表示[i,i+2j−1] 这段长度为2j 的区间中的最大值。也就是从i开始2j个数的最大值;

边界:f(i,0)=ai。即f[i,i]区间的最大值就是ai。

递推时我们把子区间的长度成倍增长,$f(i,j)=max{f(i,j−1),f(i+2j−1,j−1)}$;

状态转移:将[i,j]平均分成两段,一段为[i,i+2j−1],另一段为[i+2j−1,i+2j−1]。

即两段子区间的长度均为2j−1。f(i,j)的最大值即这两段的最大值中的最大值。

查询任意区间[l,r]时,我们先计算出一个k,满足2k<r-l+1<=2k+1;也就是使2k小于区间的前提下的最大的k,

那么“从l开始2k个数”和以r结尾的2k个数,这两段一定覆盖了整个区间[l,r],

这两段的最大值分别是f[l,k],f[r-2k+1,k],两个中较大的就是整个区间[l,r]的最值,即使重叠也没有关系;

网上也有这样解释的;https://blog.csdn.net/Hanks_o/article/details/77547380

一个查询最小值的问题:质量检测

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x)
{
x=;T f=,ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
x*=f;
}
int n,m,f[][],x,y;
inline void Rmq(int x)
{
for(int i=; i<=; i++)
{
for(int j=; j<=x; j++)
{
if(j+(<<i)-<=x)//使j+(1<<i)-1不超过区间最右端;
f[j][i]=min(f[j][i-],f[j+(<<(i-))][i-]);//动态规划;
}
}
}
inline int query(int x,int y)
{
int k=log2(y-x+);
return min(f[x][k],f[y-(<<k)+][k]);
}
int main()
{
read(n);read(m);
for(int i=;i<=n;i++)
read(f[i][]);
Rmq(n);
for(int i=;i<=n-m+;i++)
printf("%d\n",query(i,i+m-));
return ;
}

毕竟最大最小改一下min,max就可以了;

忠诚

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x)
{
x=;T f=,ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
x*=f;
}
int n,m,f[][],x,y,a[];
inline void Rmq(int x)
{
for(int i=; i<=; i++)
{
for(int j=; j<=x; j++)
{
if(j+(<<i)-<=x)
f[j][i]=min(f[j][i-],f[j+(<<(i-))][i-]);
}
}
}
inline int query(int x,int y)
{
int k=log2(y-x+);
return min(f[x][k],f[y-(<<k)+][k]);
}
int main()
{
read(n);read(m);
for(int i=;i<=n;i++)
read(f[i][]);
Rmq(n);
for(int i=;i<=m;i++)
{
read(x);read(y);
a[i]=query(x,y);
}
for(int i=;i<=m;i++)
printf("%d ",a[i]);
return ;
}

但有点变态的是,这个过不了洛谷的1440,所以我们再来讲一下单调队列的实现方式;

例题:滑动窗口

这个单调队列讲解好强:https://www.luogu.org/blog/hankeke/solution-p1886

本题样例:

8 3
1 3 -1 -3 5 3 6 7

下文中我们用q来表示单调队列,p来表示其所对应的在原列表里的序号。

  1. 由于此时队中没有一个元素,我们直接令1进队。此时,q={1},p={1}。

  2. 现在3面临着抉择。下面基于这样一个思想:假如把3放进去,如果后面2个数都比它大,那么3在其有生之年就有可能成为最小的。此时,q={1,3},p={1,2}

  3. 下面出现了-1。队尾元素3比-1大,那么意味着只要-1进队,那么3在其有生之年必定成为不了最小值,原因很明显:因为当下面3被框起来,那么-1也一定被框起来,所以3永远不能当最小值。所以,3从队尾出队。同理,1从队尾出队。最后-1进队,此时q={-1},p={3}

  4. 出现-3,同上面分析,-1>-3,-1从队尾出队,-3从队尾进队。q={-3},p={4}。

  5. 出现5,因为5>-3,同第二条分析,5在有生之年还是有希望的,所以5进队。此时,q={-3,5},p={4,5}

  6. 出现3。3先与队尾的5比较,3<5,按照第3条的分析,5从队尾出队。3再与-3比较,同第二条分析,3进队。此时,q={-3,3},p={4,6}

  7. 出现6。6与3比较,因为3<6,所以3不必出队。由于3以前元素都<3,所以不必再比较,6进队。因为-3此时已经在滑动窗口之外,所以-3从队首出队。此时,q={3,6},p={6,7}

  8. 出现7。队尾元素6小于7,7进队。此时,q={3,6,7},p={6,7,8}。

那么,我们对单调队列的基本操作已经分析完毕。因为单调队列中元素大小单调递*(增/减/自定义比较),因此,队首元素必定是最值。按题意输出即可。

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x)
{
x=;T f=,ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-; ch=getchar();}
while(isdigit(ch)) {x=x*+ch-''; ch=getchar();}
x*=f;
}
int head,tail,q[],p[],k,n,a[];
inline void maxn()
{
head=;tail=;
for(int i=;i<=n;i++)
{
while(head<=tail&&q[tail]<=a[i])
--tail;
q[++tail]=a[i];
p[tail]=i;
while(p[head]<=i-k)
head++;
if(i>=k) printf("%d ",q[head]);
}
putchar('\n');
}
inline void minn()
{
head=;tail=;
for(int i=;i<=n;i++)
{
while(head<=tail&&q[tail]>=a[i])
--tail;
q[++tail]=a[i];
p[tail]=i;
while(p[head]<=i-k)
head++;
if(i>=k) printf("%d ",q[head]);
}
putchar('\n');
}
int main()
{
read(n);read(k);
for(int i=;i<=n;i++)
read(a[i]);
minn();
maxn();
return ;
}

模板 RMQ问题ST表实现/单调队列的更多相关文章

  1. 使用类模板的C++线性表实现(数组方式)

    main.h #ifndef _MAIN_H_ #define _MAIN_H_ #include <iostream> #include <exception> #inclu ...

  2. POJ 2823 Sliding Window​ (模板题)【单调队列】

    <题目链接> <转载于>>> > 题目大意: 给你一段序列和一个长为k的窗口,这个窗口从最左边逐渐向右滑,直到滑到最右边,问你,该窗口在滑动的过程中,最大值和 ...

  3. 洛谷 P1886 滑动窗口(单调队列)

    嗯... 题目链接:https://www.luogu.org/problem/P1886 首先这道题很典型,是标准的单调队列的模板题(也有人说单调队列只能解决这一个问题).这道题可以手写一个队列,也 ...

  4. POJ1821 单调队列//ST表 优化dp

    http://poj.org/problem?id=1821 当我们在考虑内层循环j以及决策k的时候,我们可以把外层变量i看作定值,以此来优化dp状态转移方程. 题意 有n个工人准备铺m个连续的墙,每 ...

  5. 【模板】deque实现单调队列

    双端队列deque容器: 关于deque最常用的有这几个函数: 都是成员函数 双端队列模板题:[洛谷]P2952 [USACO09OPEN]牛线Cow Line #include<iostrea ...

  6. HDU - 5289 Assignment (RMQ+二分)(单调队列)

    题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相 ...

  7. HDU3183 A Magic Lamp —— 贪心(单调队列优化)/ RMQ / 线段树

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3183 题解: 方法一:贪心. 在草稿纸上试多几次可以知道,删除数字中从左到右最后一位递增(可以等于)的 ...

  8. [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)

    4540: [Hnoi2016]序列 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1567  Solved: 718[Submit][Status] ...

  9. cf1208 E Let Them Slide(差分+RMQ\单调队列)

    题意 如题目的图所示,每行都可以左右移动,但是数字不允许断开,且不许越界(宽度为w). 单独求每一列的最大的和为多少. 思路 对于每一列来说,在每一行上都有一个可以取到的区间, 所以,对于一列来说,答 ...

随机推荐

  1. jQuery效果------隐藏hide()/显示show()

    hide()和show() hide():隐藏文本. show():显示文本. 语法: $(selector).hide(speed,callback); $(selector).show(speed ...

  2. windows下创建.gitignore

    网上搜索 .gitignore 的创建,很多linux上的,而且还一样,... 尝试了几次,windows可以这样写 .svn/ .settings/ .buildpath .project

  3. Ultimate Guide to WeChat for Business 2019

    Ultimate Guide to WeChat for Business 2019 By Iaroslav Kudritskiy (source :https://rocketbots.io/blo ...

  4. 遍历二叉树 traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化

    遍历二叉树   traversing binary tree 线索二叉树 threaded binary tree 线索链表 线索化 1. 二叉树3个基本单元组成:根节点.左子树.右子树 以L.D.R ...

  5. C#中$的用法

    class Program { static void Main(string[] args) { string tbName = "User"; string colName = ...

  6. kali2.0安装docker(转)

    开始部署 1. Docker需要Linux Kernels 大于3.10并且是64-bit的机器,用uname -a可以查看是否符合要求. 2. 执行命令编辑文本: vim /etc/apt/sour ...

  7. Linux对大容量磁盘分区

    1.使用fdisk -l命令,查看可分区的磁盘 2.使用parted命令进行分区 parted /dev/sdb 3.创建分区表 mklabel 磁盘类型选择 gpt , 警告选择yes,代表清除磁盘 ...

  8. Centos7.3安装和配置Tomcat8

    1.下载tomcat8压缩包 下载地址:https://pan.baidu.com/s/1ONIq3S5YjbCsET1rA13lGA 2.通过xftp工具将压缩包上传到usr/java下,然后使用下 ...

  9. [js]练习绘制拓扑图

  10. 60道Python面试题&答案精选!找工作前必看

    需要Word/ PDF版本的同学可以在实验楼微信公众号回复关键词"面试题"获取. 1. Python 的特点和优点是什么? 答案:略. 2. 什么是lambda函数?它有什么好处? ...