[模板]ST表浅析

ST表,稀疏表,用于求解经典的RMQ问题。即区间最值问题。

Problem:

给定n个数和q个询问,对于给定的每个询问有l,r,求区间[l,r]的最大值。.

Solution:

主要思想是倍增和区间dp。

状态:dp[i][j] 为闭区间[i,i+2^j-1]的最值。

这个状态与转移方程的关系很大,即闭区间的范围涉及到了转移方程的简便性。

转移方程:dp[i][j]=max(dp[i][j-1],dp[i+2^(j-1)][j-1])

这是显然的,但这里有个细节:第一个项的范围为[i,i+2^(j-1)-1],即第i个数到第i+2^(j-1)个数的前一个数,而第二个项的范围是[i+2^(j-1),i+2^j-1]。这里容易弄混,所以导致无法理解整个方程,或者写错。

询问:[l,r]区间的最大值。

令g=log2(r-l+1)向下取整。则区间的最值就是max(dp[l][g],dp[r-2^g+1][g])

好的,我们开始对这些方程做一番分析。假设现在有5个数,为如下情况。这些分别是,dp[1][0],dp[2][0]....dp[5][0]

接着,我们可以统计到红色区域的最大值。这些分别是dp[1][1],dp[2][1]...dp[4][1]

最后,我们再统计到dp[1][2],dp[2][2],也就是1~1+4-1和2~2+4-1的最大值。

直到整个求完。(5后面的点因为皆为0,所以在取区间最大值的时候可以直接忽略)

有了这些后,如果要求l~r的最大值,我们需要让两个区间覆盖这个区间。假设我们询问1~5的最大值。

按道理来讲,我们假设2^x=5-1+1,然后dp[1][x]不就完事了?然而很可惜,x可能为小数。因此,x我们应当向下取整x‘,那么显然这样子取dp[1][x‘]会比dp[1][x]少一段。

于是我们再采用dp[5-2^x‘+1][x‘]的方式来弥补。什么意思呢?

像这样,在两个互相被覆盖的区间里取一个最大值,是不是完美的解决了这个问题呢?而这个x就等于log2(x),x‘即为log2(x)向下取整。

你可能会说这样有没有可能会没有全部覆盖,这很显然不可能。因为l+2^x‘<r-2^x‘ 等价于 2^(x‘+1)<r-l。而显然这个x‘+1>=x,所以2^(x‘+1)>2^x=r-l+1>r-l。因此原不等式绝对不成立。

以上,ST表是一个很好的倍增思想入门。在LCA中也用到了与ST表非常类似的倍增思想。

ST表很简单。请注意常数,很容易就会了。Luogu P3865即为模板题。

下面是代码:

#include<bits/stdc++.h>
using namespace std;
template <typename T> T gn(T &x){
    x=0;
    T plus=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘)plus=(ch==‘-‘?-1:1),ch=getchar();
    while(ch>=‘0‘&&ch<=‘9‘)x=x*10+ch-‘0‘,ch=getchar();
    return x*plus;
}
const int N=1e5+10;
int a[N][25];
template <typename T> inline int mmax(T &a,T &b){return a<b?b:a;}
inline int dpow(int a,int x){
    int ret=1;
    while(x){
        if(x&1)ret*=a;
        a*=a;
        x>>=1;
    }
    return ret;
}

int main(){
    int n,m;
    gn(n),gn(m);
    for(int i=1;i<=n;i++)
        gn(a[i][0]);
    int plus=1;
    for(int j=1;j<25;j++){
        for(int i=1;i+plus<=n;i++)
            a[i][j]=mmax(a[i][j-1],a[i+plus][j-1]);
        plus*=2;
    }
    int na,nb,x;
    for(int i=0;i<m;i++){
        gn(na),gn(nb);
        x=log2(nb-na+1);
        printf("%d\n",mmax(a[na][x],a[nb-dpow(2,x)+1][x]));
    }
    return 0;
}
时间: 2024-10-26 00:49:50

[模板]ST表浅析的相关文章

ST表竞赛模板

void RMQ_init(){//ST表的创建模板 for(int i=0;i<n;i++) d[i][0]=mo[i]; for(int j=1;(1<<j)<=n;j++) for(int i=0;i+(1<<j)-1<n;i++){ d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } } int RMQ_min(int L,int R){//区间最小.大值 int k=0; while((1<&l

【模板】ST表 洛谷P1816 忠诚

P1816 忠诚 题目描述 老管家是一个聪明能干的人.他为财主工作了整整10年,财主为了让自已账目更加清楚.要求管家每天记k次账,由于 管家聪明能干,因而管家总是让财主十分满意.但是由于一些人的挑拨,财主还是对管家产生了怀疑.于是他决定用一种特别的方法来判断管家的忠诚,他把每次的 账目按1,2,3…编号,然后不定时的问管家问题,问题是这样的:在a到b号账中最少的一笔是多少?为了让管家没时间作假他总是一次问多个问题. 输入输出格式 输入格式: 输入中第一行有两个数m,n表示有m(m<=100000

洛谷—— P3865 【模板】ST表

https://www.luogu.org/problemnew/show/P3865 题目背景 这是一道ST表经典题——静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1)O(1) 题目描述 给定一个长度为 NN 的数列,和 MM 次询问,求出每一次询问的区间内数字的最大值. 输入输出格式 输入格式: 第一行包含两个整数 N, MN,M ,分别表示数列的长度和询问的个数. 第二行包含 NN 个整数(记为 a_iai?),依次表示数列的第 ii 

ST表——模板(luogu3865)

题目背景 这是一道ST表经典题--静态区间最大值 请注意最大数据时限只有0.8s,数据强度不低,请务必保证你的每次查询复杂度为 O(1) 题目描述 给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值. 输入输出格式 输入格式: 第一行包含两个整数 N, M ,分别表示数列的长度和询问的个数. 第二行包含 N 个整数(记为 ai),依次表示数列的第 i 项. 接下来 M 行,每行包含两个整数 li, ri,表示查询的区间为 [ li, ri ] 输出格式: 输出包含 M

P3865 【模板】ST表

----------------------------------- 链接:P3865 ----------------------------------- st表是一个用来解决RMQ问题的表 st表是一个二维数组,表示的是i~i+2^j-1范围的最值 (这东西和区间DP好像) ---------------------------------- 初始化: 因为2^0=1; 所以说st[i][0]存的就是i~i范围的最值(就是他自己) for(int i=1;i<=n;++i){ cin>

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

【cogs58】延绵的山峰【st表】

问题描述 有一座延绵不断.跌宕起伏的山,最低处海拔为0,最高处海拔不超过8848米,从这座山的一端走到另一端的过程中,每走1米海拔就升高或降低1米.有Q个登山队计划在这座山的不同区段登山,当他们攀到各自区段的最高峰时,就会插上队旗.请你写一个程序找出他们插旗的高度. 输入文件 第1行,一个整数N(N<=10^6),表示山两端的跨度. 接下来N+1行,每行一个非负整数Hi,表示该位置的海拔高度,其中H0=Hn=0. 然后是一个正整数Q(Q<=7000),表示登山队的数量. 接下来Q行,每行两个数

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 <cstdi

ST表——————一失足成千古恨系列2

在此先祝自己这个系列写的越少越好qwq(保证不超过4篇(flag已立)) 考试原题:(绝壁是看完复联出的) 第一反应:线段树??不对,是st表.嗯,没错.哎,st表咋写来着??完了凉了. 结果:写暴搜的都有60分,结果我爆了0 qwq 80-->0,与键盘无缘嘤嘤嘤 好了开始说正事 ST表用来干什么的? 给定一个区间,求最值.上面那道题是典型的模板题(虽然有毒瘤数据会卡掉st表,但我们这里不讨论) 复杂度:预处理:O(nlogn),询问:O(1) 先说预处理. st表示一个二维数组,其中st[i