美文网首页acm混饭之路三人行
区间---RMQ区间最值查询

区间---RMQ区间最值查询

作者: 哟破赛呦 | 来源:发表于2019-01-20 17:32 被阅读10次

RMQ区间最值查询,对于长度为n的数组A[]
RMQ(i,j),返回数组A区间[i , j]内的最大值或最小值。

思路:

ST算法:
O(nlogn)预处理,O(1)查询
定义dp[i][j]表示从第i个数起连续2^j个数中(即区间[i...i+2^j-1])的最值
A={0,1,2,3},dp[0][1]=1,dp[0][2]=3.这里求最大值
初始化dp[i][0] = A[i]
转移方程:dp[i][j] = max(dp[i][j-1], dp[i+2^(j-1)][j-1])
查询:如果查询区间[i,j]内的最值,先求区间长度为j-i+1
k = log2(j-i+1),则RMQ(i,j) = max(dp[i][k], dp[j-(2^k)+1][k])

#include <iostream>
using namespace std;
namespace RMQ{
    int *A;
    int dp[100][10];//第二维大小log2(n)就行
    void init(int n){//数组长度
        for(int i=0; i<n; i++){
           dp[i][0] = A[i]; 
        }
        for(int j=1; (1<<j)<=n; j++){
            for(int i=0; i+(1<<j)-1<n; i++){
                dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int query(int l, int r){
        int k=0;  //k=log2(r-l+1)
        while((1<<k+1) <= r-l+1) k++;
        return max(dp[l][k] ,dp[r-(1<<k)+1][k]);
    }
}
int main(){
     int data[] = {3 ,2 ,4 ,5 ,6 ,8 ,1 ,2 ,9 ,7};
     RMQ::A=data;
     RMQ::init(10);
     cout<<RMQ::query(0,9)<<endl;//3....7 -> 9
     cout<<RMQ::query(1,1)<<endl;//2 -> 2
     cout<<RMQ::query(4,6)<<endl;//6 8 1 -> 8
     return 0;
}

例题

POJ3264
题目大意:
第一行输入 n,q 表示一个长度为n的数列,q组询问
接下来n行 每行一个整数表示数列内容
接下来q行 每行一个l r 表示一个区间
输出每个区间内 最大值 减去 最小值 是多少

Sample Input
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0

ac代码

#include <iostream>
#include <stdio.h>
using std::max;
using std::min;
namespace RMQ{
    int *A;
    int dp[50000][32];
    int dp2[50000][32];
    void init(int n){//数组长度
        for(int i=0; i<n; i++){
           dp[i][0] = A[i];
           dp2[i][0] = A[i];
        }
        for(int j=1; (1<<j)<=n; j++){
            for(int i=0; i+(1<<j)-1<n; i++){
                dp[i][j] = max(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
                dp2[i][j] = min(dp2[i][j-1], dp2[i+(1<<(j-1))][j-1]);
            }
        }
    }
    int query(int l, int r){
        int k=0;  //k=log2(r-l+1)
        while((1<<k+1) <= r-l+1) k++;
        return max(dp[l][k] ,dp[r-(1<<k)+1][k])-min(dp2[l][k] ,dp2[r-(1<<k)+1][k]);
    }
}
int data[50000];
int main(){
    int n,q;
    scanf("%d %d",&n,&q);
    for(int i=0;i<n;++i){
        scanf("%d",&data[i]);
    }
    RMQ::A=data;
    RMQ::init(n);
    int l,r;
    while(q--){
        scanf("%d %d",&l,&r);
        printf("%d\n",RMQ::query(l-1,r-1));
    }
     return 0;
}

相关文章

  • 区间---RMQ区间最值查询

    RMQ区间最值查询,对于长度为n的数组A[]。RMQ(i,j),返回数组A区间[i , j]内的最大值或最小值。 ...

  • Fenwick Tree/B.I.T树状数组算法

    树状数组适用范围:给定区间,求最值,求和,区间单点修改。与RMQ不同的是,RMQ一般只用作区间求最值。但在最值方面...

  • 线段树 + 树状数组 + ST表 模板

    线段树 区间修改+区间求和 logN 树状数组 区间求和+单点修改 logN ST表 离线查询区间最值 构造Nlo...

  • 线段树(区间树)--Segement Tree

    用于解决的问题: 对于给定区间 更新:更新区间中一个元素或者一个区间的值 查询一个区间[i,j]的最大值,或者区间...

  • poj3264(区间最值问题RMQ)

    题目大意:给出一串数字,然后给出一个区间a b,输出从a到b的最大的数和最小的数的差。 N(1 ≤ N ≤ 500...

  • (RMQ)Range Minimum/Maximum Query

    RMQ适用范围:给定区间,求最值。 预处理(构造):对于第0行:存取范围为j~j的数字(本身)对于第1行:存取范围...

  • 线段树

    一、线段树建树、单点修改、区间查询 二、线段树建树、区间修改、区间查询

  • 支持区间修改和区间查询的线段树

    这种线段树支持区间修改和区间查询,区间修改的操作通过懒惰标记(lazy tag)实现。 一道支持区间修改和区间查询...

  • 我爱线段树

    单点更新单点查询的单点更新范围查询的范围更新单点查询的范围更新范围查询的求和的权值的区间最值的不带lazy标记的一...

  • 最值

    WIKI 1 利用导数求函数在闭区间上的最值 利用导数求函数在开区间的最值 应用

网友评论

    本文标题:区间---RMQ区间最值查询

    本文链接:https://www.haomeiwen.com/subject/qiwxjqtx.html