算法笔记--st表

概述:用倍增法求区间最值的离线算法,O(nlogn)预处理,O(1)访问。

预处理:

  状态:st[i][j]:[i,i+2^j)之间的最值  

  状态转移:如果j等于0,st[i][j]=a[i]

       如果j大于0,st[i][j]=max(st[i][j-1],st[i+2^(j-1)][j-1])或st[i][j]=min(st[i][j-1],st[i+2^(j-1)][j-1])

访问:

  求[l,r]区间里的最值

  k=floor(log(r-l+1))

  ans=max(st[l][k],st[r-2^k+1][k])或ans=min(st[l][k],st[r-2^k+1][k])

模板:

int st[N][20],a[N];
void init_st(int n){
    for(int i=n;i>=1;i--){
        st[i][0]=a[i];
        for(int j=1;i+(1<<j-1)-1<=n;j++){
            st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
        }
    }
}
int query(int l,int r){
    int k=floor(log(r-l+1)/log(2));
    return min(st[l][k],st[r-(1<<k)+1][k]);
}

 例题:POJ - 3264

思路:求区间最值差

代码:

#include<iostream>
#include<cstdio>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
int ss[N][20],st[N][20],a[N];
void init_st(int n){
    for(int i=n;i>=1;i--){
        st[i][0]=a[i];
        ss[i][0]=a[i];
        for(int j=1;i+(1<<j-1)-1<=n;j++){
            st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]);
            ss[i][j]=max(ss[i][j-1],ss[i+(1<<j-1)][j-1]);
        }
    }
}
int query(int l,int r){
    int k=floor(log(r-l+1)/log(2));
    return max(ss[l][k],ss[r-(1<<k)+1][k])-min(st[l][k],st[r-(1<<k)+1][k]);
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n,q,l,r;
    cin>>n>>q;
    for(int i=1;i<=n;i++)cin>>a[i];
    init_st(n);
    while(q--){
        cin>>l>>r;
        cout<<query(l,r)<<endl;
    }
    return 0;
}
View Code

参考:https://www.cnblogs.com/AireenYe/p/6270518.html

原文地址:https://www.cnblogs.com/widsom/p/8320838.html