RMQ-ST算法

  RMQ(Range Minimum/Maximum Query),即区间最值查询,是指这样一个问题:对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j之间的最小/大值。这两个问题是在实际应用中经常遇到的问题。最简单的算法就是对每次查询进行一次遍历,复杂度为O(QN),其中Q为查询的次数。当然有效率更高的算法。RMQ-ST算法。

  在线算法(ST算法)解决这个问题。所谓在线算法,是指用户每输入一个查询便马上处理一个查询。该算法一般用较长的时间做预处理,待信息充足以后便可以用较少的时间回答每个查询。ST(Sparse Table)算法是一个非常有名的在线处理RMQ问题的算法,它可以在O(nlogn)时间内进行预处理,然后在O(1)时间内回答每个查询。

  首先是预处理,用动态规划(DP)解决。设A[i]是要求区间最值的数列,F[i, j]表示从第i个数起连续2^j个数中的最大值。例如数列3 2 4 5 6 8 1 2 9 7,F[1,0]表示第1个数起,长度为2^0=1的最大值,其实就是3这个数。 F[1,2]=5,F[1,3]=8,F[2,0]=2,F[2,1]=4……从这里可以看出F[i,0]其实就等于A[i]。这样,DP的状态、初值都已经有了,剩下的就是状态转移方程。我们把F[i,j]平均分成两段(因为f[i,j]一定是偶数个数字),从i到i+2^(j-1)-1为一段,i+2^(j-1)到i+2^j-1为一段(长度都为2^(j-1))。用上例说明,当i=1,j=3时就是3,2,4,5 和 6,8,1,2这两段。F[i,j]就是这两段的最大值中的最大值。于是我们得到了动态规划方程F[i, j]=max(F[i,j-1], F[i + 2^(j-1),j-1])。然后是查询。取k=[log2(j-i+1)],则有:RMQ(A, i, j)=min{F[i,k],F[j-2^k+1,k]}。 举例说明,要求区间[2,8]的最大值,就要把它分成[2,5]和[5,8]两个区间,因为这两个区间的最大值我们可以直接由f[2,2]和f[5,2]得到。

题目详见#1068 : RMQ-ST算法,附上AC代码。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
using namespace std;

const int N = 10e6+10;
const int M = 30;
int arrayData[N];
int rmqData[N][M];
int n,m;
int min(int x, int y){
    return (x <y ? x : y);
}
void RMQ(){
    int i, j;
    for (i = 0; i < n; i++){
        rmqData[i][0] = arrayData[i];
    }
    for (j = 1; j <=m; j++){
        for (i = 0; i+(1 << j)-1 <n; i++){
            rmqData[i][j] = min(rmqData[i][j - 1], rmqData[i + (1<<(j - 1))][j - 1]);
        }
    }
}

int main(){
    scanf("%d", &n);
    int i, j;
    for (i = 0; i < n; i++){
        scanf("%d", &arrayData[i]);
    }
    m = (log(n*1.0) / log(2.0));

    RMQ();

    int q;
    scanf("%d", &q);
    for (i = 0; i < q; i++){
        int l, r;
        scanf("%d%d", &l, &r);
        l = l - 1;
        r = r - 1;
        int k=0;
        while ((1 << (k + 1)) <= (r - l + 1)) k++;
        printf("%d\n", min(rmqData[l][k], rmqData[r-(1<<k)+1][k]));
    }
    return 0;
}
时间: 2024-10-01 03:36:44

RMQ-ST算法的相关文章

[POJ3264]Balanced Lineup(RMQ, ST算法)

题目链接:http://poj.org/problem?id=3264 典型RMQ,这道题被我鞭尸了三遍也是醉了…这回用新学的st算法. st算法本身是一个区间dp,利用的性质就是相邻两个区间的最值的最值一定是这两个区间合并后的最值,这条性质决定了这个dp子问题的重叠.可以利用这个性质预处理出这张表,只不过步长是2的幂次. 查询的时候也是如此,但是未必会精准地选中两个区间,不要紧,因为两个区间重叠的部分也会被自动算在求最值的内部.这个时候如果算的是区间和的话,要减去这一部分.(区间和的话直接用前

CF359D Pair of Numbers [RMQ+ST算法]

题意: 给一串数,找出最长的区间使得这个区间里面有个数能被其他所有数整除(包括它自己),求满足这个条件的最长区间的个数及长度,以及这些区间的左端的位置 分析: 这个区间的要求其实就是GCD(ALL)=MIN(ALL),能被其他数整除,这个数肯定是最小的,然后又能被其他数整除(包括自己)这个数就是GCD了 可以二分枚举区间长度,然后验证答案的可靠性 对当前长度的所有区间,套用RMQ,验证是否存在一个区间的GCD=MIN 如果有这样的一个区间,那么说明当前长度可以,加大枚举的区间长度,否则减小 #i

POJ3264 Balanced Lineup 线段树 RMQ ST算法应用

Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 36813 Accepted: 17237 Case Time Limit: 2000MS Description For the daily milking, Farmer John's N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John de

POJ 3368 Frequent values RMQ ST算法/线段树

                                                     Frequent values Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 15229   Accepted: 5550 Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasing order. In

自己写的 RMQ ST算法模板类

1 #include<iostream> 2 using namespace std; 3 #include<cstdio> 4 #include<cstring> 5 /* 6 说明: 7 RMQ<T> rr;定义一个查询区间最小值的数据类型为T 的类 8 SetMaxn(T maxn);设置初始化数组的最大值 9 Creat(T a[],int maxn) 设置查询的数组,和数组长度,从0开始 10 Getx(int la,int lb) 查询数组中下标

RMQ st算法 区间最值模板

#include<bits/stdc++.h> const int N=1e6+5; const int Logn=20; int f[N][Logn],a[N],lg[N],n,m; int main(){ cin>>n>>m; rep(i,1,n) cin>>a[i]; lg[0]=-1; rep(i,1,n) fa[i][0]=a[i],lg[i]=lg[i>>1]+1; rep(j,1,Logn) for(int i=1;i+(1<

RMQ问题——ST算法

什么是RMQ.ST:RMQ(Range Minimum/Maximum Query)问题,即求区间的最值.可以写一个线段树来实现,但是每次查询的时间复杂度为O(log n),若查询次数过多则可能超时.ST算法是一种离线算法,经过O(nlogn)的预处理后,可以在O(1)的时间复杂度内进行查询,缺点是无法对数据做出修改. 算法实现: 初始化:用dp实现初始化.a[]为原始数据数组f,[i][j]表示从i向后的2j个数字中的最值.显然f[i][0]=a[i]; 我们将f[i][j]分为两段,一段为a

理解RMQ问题和ST算法的原理

下图为TI C6xx DSP Nyquist总线拓扑图,总线连接了master与slave,提供了高速的数据传输.有很多种速率不同的总线,如图中的红色方框,最高速总线为CPU/2 TeraNet SCR(即VBUSM SCR),带宽为256bit,其他低速总线为CPU/3,CPU/6,带宽参考图中所示.总线之间用Bridge(桥)连接,作用包括转换总线的速率,使之与所流向总线的速率相同等. 在具体应用中,各种速率的总线完全可以满足复杂的数据传输,而数据传输的瓶颈往往在于连接总线之间的Bridge

RMQ问题之ST算法

RMQ问题之ST算法 RMQ(Range Minimum/Maximum Query)问题,即区间最值问题.给你n个数,a1 , a2 , a3 , ... ,an,求出区间 [ l , r ]的最大值. 举例:a={ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 },求出区间[4 ,8]中的最值.(答案:8 ) 这个问题最朴素的想法是用一个循环每次比较大小,但是,当数据范围较大时,这个算法十分低效.这时我们往往使用 ST 算法解决这个问题.虽然线段树和树状数组都能解决,但

LCA最近公共祖先 ST+RMQ在线算法

对于这一类的问题有2中解决方法.第一种就是tarjan的离线算法,还有一中是基于ST算法的在线算法.复杂度都是O(n); 先介绍在线算法: 1) dfs: 对于图所示的树,我们从根节点1开始dfs,按照先序访问(不算完全的先序),那么它访问顺序就是1 -> 2 -> 4 -> 2 -> 5 -> 7 -> 5 -> 8 -> 5 -> 2 -> 1 -> 3 -> 1 然后用数组first存第一次访问到该点时的时间(也就是访问顺序里面