小李的算法笔记(一道简单的ST表算法模版题)

//题目大意:第一行给出N,Q两个数,(1<=N<=50000;1<=Q<=200000)接下来n行每一行有一个数,
//再接下来有Q组查询,每行查询给出一个区间[l,r](1<=l<=r<=N),输出该区间内最大值和最小值的差值。
//输入
//6 3
//1
//7
//3
//4
//2
//5
//1 5
//4 6
//2 2
//输出
//6
//3
//0

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

int a[50005];
int fmaxn[50005][50];//fmax[i][j]表示从第i位起,向后2^j范围内的最大值
int fminn[50005][50];//fmin[i][j]表示从第i位起,向后2^j范围内的最小值
int n,q;

void ST_work(){//建立ST表
    for(int i=0;i<n;++i)
    {
        fmaxn[i][0]=fminn[i][0]=a[i];//表示区间[i,i]范围,即初值
    }
    int t=log(n)/log(2)+1;//即要满足(1<<j)<=n
    for(int j=1;j<t;++j)
        for(int i=0;i<=n-(1<<j);++i){
            //利用状态转移方程f[i][j]=max(or min)(f[i][j-1],f[i+(1<<j-1)][j-1]);
            //即将区间(i,i+2^j)分成两个子区间(i,i+2^(j-1))和(i+2^(j-1),i+2^(j-1)+2^(j-1));
            fmaxn[i][j]=max(fmaxn[i][j-1],fmaxn[i+(1<<(j-1))][j-1]);
            fminn[i][j]=min(fminn[i][j-1],fminn[i+(1<<(j-1))][j-1]);
            
        }
}

int ST_max(int l,int r){
    int k=log(r-l+1)/log(2);
    //区间长度为r-l+1,化为指数形式以便进行划分子区间
    //[l,r]区间被划为[l,l+2^k]和[l+1,l+1+2^k];这样划分的目的是防止有些区间被遗失
    return max(fmaxn[l][k],fmaxn[r-(1<<k)+1][k]);
}

int ST_min(int l,int r){
    int k=log(r-l+1)/log(2);
    return min(fminn[l][k],fminn[r-(1<<k)+1][k]);
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=0;i<n;++i)
    {
        scanf("%d",&a[i]);
    }
    ST_work();
    int l,r;
    while(q--)
    {
        scanf("%d%d",&l,&r);
        l--;//与数组下标对齐
        r--;
        printf("%d\n",ST_max(l,r)-ST_min(l,r));
    }
    return 0;
}

​​​​​​​如有错误,欢迎指出!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值