RMQ—ST表

一、简介

ST算法应用于RMQ问题,能在O(nlogn)内预处理,O(1)时间查询。
思想:应用倍增的思想,选取2的次幂为代表值。

二、预处理ST_prework()

设立 d p [ i ] [ c n t ] dp[i][cnt] dp[i][cnt]代表从 i i i i + 2 c n t − 1 i + 2 ^{cnt} - 1 i+2cnt1中最大的值。
我们将其从中间分成两部分 d p [ i ] [ c n t − 1 ] dp[i][cnt - 1] dp[i][cnt1] d p [ i + 2 c n t − 1 ] [ c n t − 1 ] dp[i + 2^{cnt - 1}][cnt - 1] dp[i+2cnt1][cnt1]
我们划分块的最大长度为 2 t > = n 2^t >= n 2t>=n t = l o g ( n ) / l o g ( t ) t = log(n) / log(t) t=log(n)/log(t)

void ST_perwork(int l,int r){
    for(int i = 1;i <= r; i++) 
        dp[i][0] = a[i];
    int t = log(r) / log(2);
    for(int j = 1; j <= t; j++)//分成的块
        for(int i = 1; i <= r - ( 1<<(j) ) + 1;i++){
            dp[i][j] = max(dp[i][j-1] , dp[i + (1<<(j - 1))][j - 1] ) ;
        }//枚举左端点
}

三、询问函数ST_query()

找到 2 t < = r − l + 1 < = 2 t + 1 2^t <= r - l + 1 <= 2 ^{t+1} 2t<=rl+1<=2t+1 2 t 2^t 2t小于长度的最大值。
同样,我们分为两个区间 l l l开始的 2 t 2^{t} 2t长度 和 r r r为结尾 2 t − 1 2^{t-1} 2t1位长度。

int ST_query(int l,int r){
    int t = log(r - l + 1) / log(2);
    return max(dp[l][t],dp[r - ( 1 << (t)) + 1][t]);
}

四、模板

ST表

/*
 * @Author: NEFU_马家沟老三
 * @LastEditTime: 2020-08-26 23:20:25
 * @优快云 blog: https://blog.youkuaiyun.com/acm_durante
 * @E-mail: 1055323152@qq.com
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const ll mod = 1e9 + 7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
template<class T>inline void read(T &res)
{
char c;T flag=1;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}
const int N = 1e5+5;
int a[N];
int dp[N][25];
void ST_perwork(int l,int r){
    for(int i = 1;i <= r; i++) 
        dp[i][0] = a[i];
    int t = log(r) / log(2);
    for(int j = 1; j <= t; j++)//分成的块
        for(int i = 1; i <= r - ( 1<<(j) ) + 1;i++){
            dp[i][j] = max(dp[i][j-1] , dp[i + (1<<(j - 1))][j - 1] ) ;
        }//枚举左端点
}
int ST_query(int l,int r){
    int cnt = log(r - l + 1) / log(2);
    return max(dp[l][cnt],dp[r - ( 1 << (cnt)) + 1][cnt]);
}
int main()
{
    int n,m;
    read(n);read(m);
    rep(i,1,n) read(a[i]);
    ST_perwork(1,n);
    while (m--)
    {
        int l,r;
        read(l),read(r);
        printf("%d\n",ST_query(l,r));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值