RMQ与st表

模板题
P3865 【模板】ST表

代码

实质也是DP,利用倍增获取从i开始长度为\(2^0,2^1,2^2…2^j\)的区间内的最大值。
这样对于任意区间\([l,r]\)都有,令\(dis=r-1+1\)则有\(k_0=2^c,2^{k_0}≤dis≤2^{k_0+1}\)这样在区间\([l,l+k0-1],[r-k0+1,r]\)完全覆盖了这个区域(中间可能有重叠)

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int dp[100100][20];
int a[100100];
int lg[100100];
int n,m;
void st(){
    for(int i=1;i<=n;i++){
        dp[i][0]=a[i];
    }
    for(int j=1;(1<<j)<=n;j++){
        for(int i=1;i+(1<<j)-1<=n;i++){
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
// 方法2
//    int k=0;
//    for(int i=1;i<=n;i++){
//        if(i<=(1<<(k))){
//            lg[i]=k;
//        }else{
//            k++;
//            lg[i]=k;
//        }
//    }
}
int RMQ(int l,int r){
    int k=0;
//  方法2
//  k=lg[r-l+1]-1;

//  方法3
//    while((1<<(k+1))<=r-l+1){
//      k++;
//  }

//  方法1
    k=(double)log(r-l+1)/log(2);
    return max(dp[l][k],dp[r-(1<<k)+1][k]);
}
void init(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
}
int main(){
    init();
    st();
    // cout<<RMQ(1,5);
    int q,w;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q,&w);
        printf("%d\n",RMQ(q,w));
    }
}

计算log的方法可以提前用O(n)的预处理(方法2)或者每次lgn的计算(常数很小,基本上可以忽略)或者不知道常数的。。log算法
反正从代码上来看时间,log\(<\)预处理\(<\)\(O(lgn)\)计算
分别是1112ms 1224ms 1648ms
洛谷评测

原文地址:https://www.cnblogs.com/zhshh/p/rmqst.html

时间: 2024-10-17 03:26:06

RMQ与st表的相关文章

RMQ问题 - ST表的简单应用

2017-08-26 22:25:57 writer:pprp 题意很简单,给你一串数字,问你给定区间中最大值减去给定区间中的最小值是多少? 用ST表即可实现 一开始无脑套模板,找了最大值,找了最小值,分别用两个函数实现,实际上十分冗余 所以TLE了 之后改成一个函数中同时处理最大值和最小值,就可以了 AC代码如下: /* @theme:poj 3264 @writer:pprp @declare:ST表(sparse table)稀疏表,用动态规划的思想来解决RMQ问题: @date:2017

Codeforces 803G Periodic RMQ Problem ST表+动态开节点线段树

思路: (我也不知道这是不是正解) ST表预处理出来原数列的两点之间的min 再搞一个动态开节点线段树 节点记录ans 和标记 lazy=-1 当前节点的ans可用  lazy=0 没被覆盖过 else 区间覆盖 push_up的时候要注意好多细节,, 数组尽量往大开 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const in

【倍增】RMQ的ST表算法

RMQ问题:给定一个长度为N的区间,M个询问,每次询问Li到Ri这段区间元素的最大值/最小值. RMQ的高级写法一般有两种,即为线段树和ST表. 本文主要讲解一下ST表的写法.(以区间最大值为例) ST表:一种利用dp求解区间最值的倍增算法. 定义:f[i][j]表示i到i+2^j-1这段区间的最大值. 预处理:f[i][0]=a[i].即i到i区间的最大值就是a[i]. 状态转移:将f[i][j]平均分成两段,一段为f[i][j-1],另一段为f[i+2^(j-1)][j-1]. 两段的长度均

(ST表+二分+前缀和)CSU 1879 - Hack Protection

题意: 给定一个序列,求异或和与按位与和相同的区间有几个. 异或和:n个数异或起来.按位与和类似. 分析: 这才是神题,基础算法大杂烩. 问大佬这题的时候,人家只说很不难啊.. 只能说自己太菜. 由于询问区间个数,自然要快速知道某一个区间的异或和与按位与和. 异或和很简单,利用他的性质,直接求前缀和即可. 但是按位与没有和加法和异或类似的性质,无法直接求出. 但是利用之前的知识可以将所有结果预处理出来,而且只要nlogn的复杂度. 就是之前搞RMQ的ST表,很适合离线查询. 几乎不用动的把 mi

RMQ ST表

//ST表 //计算RMQ 即区间最值 //思想:区间dp+倍增 //注:将代码内所有max改成min即可求最小值 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; int n,m,l,r,a[100001]; int Pow[3

二维st表,一种暴力但却快速的二维RMQ利器

先上例题:[HAOI2007]理想的正方形 大部分人都用单调队列,但我不会.首先我们可以暴力枚举所有的可能的正方形,每次我们需要查询RMQ,如果用朴素的方法总复杂度就会变成N^4,你不T谁T 那怎么办,总不可能写正解吧,我们可以用二维st表,预处理N^2logN,每次O(1)查询,N^2水过. 注意,强制类型转换要用大括号括起要转换的东西,例如 (int)(log(n)/log(2)); Code: #include<iostream> #include<cstdio> #incl

HDU 2586 How far away ? &lt;&lt; LCA转RMQ+ST表 求树上任两点最短距离裸题

此题还有LCA+tarjin离线查询做法,详见这里 关于ST表 解决RMQ问题,dp[i][j]表示从第i位开始长度为(1<<j)的区间的最值 维护的时候采用倍增思想,维护dp[i][j+1]=opt(dp[i][j],dp[i+(1<<j)][j]) 查询的时候,两端点为l,r,则长度len=r-l,寻找一个k,使(1<<k)大于等于len/2,这样就使得 [l,l+(1<<k)]和[r-(1<<k),r]覆盖整个区间 然后此时,就可以直接用s

K-th occurrence(后缀树组+划分树+ST表+RMQ+二分)

2019CCPC网络选拔赛1003 HDU6704 题目大意: T个测试样例.一个长度为N的字符串S,之后Q个[l,r,k],表示一个子串S[l,r],求出第k个该子串的下标.起始坐标为1.不存在输出-1. 数据范围:1≤T≤20,  1≤N≤105,  1≤Q≤105,  1≤l≤r≤N,  1≤k≤N,  |S|=N; 赛后补题.参考题解说后缀树组+划分树+ST表+二分. 比赛的时候只会后缀树组不会划分树,赛后仔细想,觉得后缀数组可以,然而并不,会TLE. 补提的时候先是采用后缀树组+划分树

倍增思想到ST表RMQ

Balanced Lineup Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 36864   Accepted: 17263 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 Joh