RMQ ( 范围最小值查询 ) 问题是一种动态查询问题,它不需要修改元素,但要及时回答出数组 A 在区间 [l, r] 中最小的元素值。

RMQ(Range Minimum/Maximum Query):对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。

对于 RMQ ,我们通常关心两方面的算法效率:预处理时间和查询时间。
解决一般 RMQ 问题的三种方法
胜者树 (Winner Tree) O(n)-O(logn)
稀疏表 (Sparse Table) O(nlogn)-O(1)
线段树 (Segment Tree) O(n)-O(logn)
这里介绍一个稀疏表算法。

一、稀疏表ST算法--预处理

二、稀疏表ST算法--查询

三、RMQ ST模板

package ads;

public class RMQ_ST {

    int[] a;
int[][] st;//st[i][j],i表示数组a的索引为i的元素,即i:索引
int n;
public RMQ_ST(int[] a) {
this.a = a;
this.n = a.length;
st = new int[n][17];
} void initRMQ() {
int k = (int)(Math.log((double)n) / Math.log(2.0));
for (int i=0; i<n; i++) st[i][0] = i;
for (int j=1; j<=k; j++) { //dp开始,从1到k
for (int i=0; i<n; i++) { //遍历每个元素
st[i][j] = st[i][j-1]; //先赋值为前一半的RMQ值
int part = i + (1 << (j-1));//后一半的第一个元素索引
if (part >= n) break; //如果后一半的第一个元素已经超出数组范围,直接跳过后面的元素
if (a[ st[i][j-1] ] > a[ st[part][j-1] ]) st[i][j] = st[part][j-1];
}
}
} int rmq(int x, int y) {
int k = (int)(Math.log((double)y-x+1) / Math.log(2.0));
int part = y - (1<<k) + 1;//切分,比如0~4切分成st(0,2)和st(1,2),前者是0~3的最小元素,后者是1~4的
if (a[ st[x][k] ] < a[ st[part][k] ]) return st[x][k];
return st[part][k];
} public static void main(String[] args) {
int[] numbers = {4,3,2,1,6,7,8,9};
RMQ_ST st = new RMQ_ST(numbers);
st.initRMQ();
System.out.println(st.rmq(0, 3));
System.out.println(st.rmq(4, 7));
} }

四、示例代码

poj2425 http://poj.org/problem?id=2452

思路:枚举每个位置 i ,找出右边第一个比 a[i] 小的元素位置j

  在 i 到 j-1 中间求最大值的位置 k ,如果 a[k] > a[i],那么更新答案

Description

Xuanxuan has n sticks of different length. One day, she puts all her sticks in a line, represented by S1, S2, S3, ...Sn. After measuring the length of each stick Sk (1 <= k <= n), she finds that for some sticks Si and Sj (1<= i < j <= n), each stick placed between Si and Sj is longer than Si but shorter than Sj.

Now given the length of S1, S2, S3, …Sn, you are required to find the maximum value j - i.

Input

The input contains multiple test cases. Each case contains two lines. 
Line 1: a single integer n (n <= 50000), indicating the number of sticks. 
Line 2: n different positive integers (not larger than 100000), indicating the length of each stick in order.

Output

Output the maximum value j - i in a single line. If there is no such i and j, just output -1.

Sample Input

4
5 4 3 6
4
6 5 4 3

Sample Output

1
-1

Source

 
#include <iostream>
#include <cstdio>
#include <cmath> using namespace std; const int MAXN = ; int n;
int a[MAXN];
int st1[MAXN][], st2[MAXN][];//分别是最小RMQ和最大RMQ
int d[]; void rmqinit() {
for (int i=; i<=n; i++) st1[i][] = st2[i][] = i;
int k = int(log(double(n)) / log(2.0)) + ;
for (int j=; j<k; j++) {
for (int i=; i<n; i++) {
st1[i][j] = st1[i][j-];
st2[i][j] = st2[i][j-];
int part = i + ( << (j-));
if (part >= n) break;
if (a[ st1[i][j-] ] > a[ st1[part][j-] ]) st1[i][j] = st1[part][j-];
if (a[ st2[i][j-] ] < a[ st2[part][j-] ]) st2[i][j] = st2[part][j-];
}
}
} int rmqmin(int l, int r) {
int k = int( log(double(r-l+)) / log(2.0) );
int part = r - (<<k) + ;
if (a[ st1[l][k] ] < a[ st1[part][k] ]) return st1[l][k];
return st1[part][k];
} int rmqmax(int l, int r) {
int k = int( log(double(r-l+)) / log(2.0) );
int part = r - (<<k) + ;
if (a[ st2[l][k] ] > a[ st2[part][k] ]) return st2[l][k];
return st2[part][k];
} int bin_search(int a) {
int l = a, r = n - ;
while (l < r) {
int mid = ((l+r)>>) + ((l+r)&);
if (a == rmqmin(a, mid)) { //如果l~mid范围内的最小元素是l,说明l~mid都大于元素l
l = mid;
}
else {
r = mid - ;
}
}
return l;
} int work() {
int res = -;
for (int i=; i<n; i++) {
int r = rmqmax(i, bin_search(i));
res = max(res, r-i);
}
if (res == ) return -;
return res;
} int main()
{
while (scanf("%d", &n) != EOF) {
for (int i=; i<n; i++) {
scanf("%d", a+i);
} rmqinit();
printf("%d\n", work());
} //cout << "Hello world!" << endl;
return ;
}

RMQ (Range Minimal Query) 问题 ,稀疏表 ST的更多相关文章

  1. 算法学习 - ST表 - 稀疏表 - 解决RMQ问题

    2017-08-26 21:44:45 writer:pprp RMQ问题就是区间最大最小值查询问题: 这个SparseTable算法构造一个表,F[i][j] 表示 区间[i, i + 2 ^ j ...

  2. 基于稀疏表(Sparse Table)的RMQ(区间最值问题)

    在RMQ的其他实现方法中,有一种叫做ST的算法比较常见. [构建] dp[i][j]表示的是从i起连续的2j个数xi,xi+1,xi+2,...xi+2j-1( 区间为[i,i+2j-1] )的最值. ...

  3. 动态规划——稀疏表求解RMQ问题

    RMQ (Range Minimum/Maximum Query)问题,即区间最值查询问题,是求解序列中的某一段的最值的问题.如果只需要询问一次,那遍历枚举(复杂度O(n))就是最方便且高效的方法,但 ...

  4. ST (Sparse Table:稀疏表)算法

    1541:[例 1]数列区间最大值 时间限制: 1000 ms         内存限制: 524288 KB提交数: 600     通过数: 207 [题目描述] 输入一串数字,给你 MM 个询问 ...

  5. AOJ DSL_2_A Range Minimum Query (RMQ)

    Range Minimum Query (RMQ) Write a program which manipulates a sequence A = {a0,a1,...,an−1} with the ...

  6. Range Minimum Query and Lowest Common Ancestor

    作者:danielp 出处:http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAnc ...

  7. AOJ DSL_2_E Range Add Query (RAQ)

    Range Add Query 数列 A = {a1,a2,...,an} に対し.次の2つの操作を行うプログラムを作成せよ. add(s,t,x): as,as+1,...,at にxを加算する. ...

  8. AOJ DSL_2_D Range Update Query (RUQ)

    Range Update Query 数列 A = {a0,a1 ,...,an−1} に対し.次の2つの操作を行うプログラムを作成せよ. update(s,t,x): as,as+1,...,at  ...

  9. [LeetCode] Range Sum Query 2D - Mutable 二维区域和检索 - 可变

    Given a 2D matrix matrix, find the sum of the elements inside the rectangle defined by its upper lef ...

随机推荐

  1. commandname+commandargument

    (一) CommandName:其实可以设置成一种动作,比如Select,Update,Delete,等操作.就是说CommandName是确定他到底引发的是哪一事件,如果CommandName的名字 ...

  2. 用php随机生成福彩双色球号码的2种方法

    不瞒您说,俺也是个双色球爱好者,经常买,但迟迟没有中过一等奖,哈哈.这里为大家介绍用php随机生成福彩双色球号码的二种方法,供朋友们学习参考.新的一年,祝大家中大奖,发大财. 方法一 复制代码代码如下 ...

  3. PHP调用java的class

    PHP调用java的class   转:http://hi.baidu.com/lei0827/blog/item/28439a4e923234ced1c86a18.html PHP调用java的cl ...

  4. 什么是blob,mysql blob大小配置介绍

    什么是blob,mysql blob大小配置介绍 作者: 字体:[增加 减小] 类型:转载   BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的容器.在计 ...

  5. empty($w)

    <?php $w = ''; var_dump(empty($w)); $w = ' '; var_dump(empty($w)); $w = 0; var_dump(empty($w)); v ...

  6. Android 加入一个动作按钮

    在XML中声明一个动作按钮 所有的动作按钮和其他的可以利用的items都定义在menu资源文件夹中的XML文件中.为了增加一个动作按钮到工具栏,需要在工程 /res/menu/ 目录下面创建一个新的X ...

  7. [Virtualization][SDN] VXLAN到底是什么 [转]

    写在转发之前: 几个月以前,在北大机房和燕园大厦直接拉了一根光钎.两端彼此为校园内公网IP.为了方便连接彼此机房,我做个一个VPN server在燕园的边界,北大机房使用client拨回.两个物理机房 ...

  8. 读书笔记——《图解TCP/IP》(4/4)

    经典摘抄 第八章 应用层协议概要 1.应用协议是为了实现某种应用而设计和创造的协议. 2.TCP/IP的应用层包含了管理通信连接的会话层功能.转换数据格式的表示层功能,还包括与对端主机交互的应用层功能 ...

  9. linux configure

    Linux环境下的软件安装,并不是一件容易的事情;如果通过源代码编译后在安装,当然事情就更为复杂一些;现在安装各种软件的教程都非常普遍;但万变不离其中,对基础知识的扎实掌握,安装各种软件的问题就迎刃而 ...

  10. Lazarus for Raspbian安装

    春节前看到树莓派 2代开始销售,第一时间在淘宝下单购买,无奈春节期间放假,要到3月份才可能收到,只能用QEMU模拟器先熟悉树莓系统.对从turbo Pascal开始的人来讲,如果能在树莓系统使用Pas ...