洛谷 P3865 ST表

 

 

ST表

ST表的功能很簡單html

它是解決RMQ問題(區間最值問題)的一種強有力的工具ios

它能夠作到O(nlogn)預處理,O(1)查詢最值數組

是一種處理靜態區間可重複計算問題的數據結構,通常也就求求最大最小值辣。數據結構

ST表的思想是先求出每一個[i, i + 2^k)的最值。工具

注意到這樣區間的總數是O(N log N)的.spa


預處理code

不妨令fi,j爲[i, i + 2^j)的最小值。htm

那麼首先fi,0的值都是它自己。blog

而fi,j = min(fi,j−1, fi+2^j−1,j−1)ip

這樣在O(N log N)的時間內就處理好了整個ST表

詢問

好比咱們要詢問[l, r]這個區間的最小值.

找到最大的k知足2^k ≤ r − l + 1.

取[l, l + 2^k), [r − 2^k + 1, r + 1)這兩個區間。

注意到這兩個區間徹底覆蓋了[l, r],因此這兩個區間最小值

較小的一個就是[l, r]的最小值。

注意到每次詢問只要找區間就好了,因此複雜度是O(1).

 

解釋一下數組含義:

ST[j][i]爲從j開始的長度爲2^i的區間的最大值

Log[x]爲比x小的最大的2^y 的y值(或者說是log x 下去整

代碼: 

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<time.h>
#include<queue>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-1);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define fi first
#define sc second
ld eps=1e-9;
ll pp=1000000007;
ll mo(ll a,ll pp){if(a>=0 && a<pp)return a;a%=pp;if(a<0)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=1;for(;b;b>>=1,a=mo(a*a,pp))if(b&1)ans=mo(ans*a,pp);return ans;}
ll read(){
    ll ans=0;
    char last=' ',ch=getchar();
    while(ch<'0' || ch>'9')last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans;
    return ans;
}
//head

int m,n,a[100001],st[100001][17],Log[100001];

int find(int a,int b)
{
    int t=Log[b-a+1];
    return max(st[a][t],st[b-(1<<t)+1][t]);
    //注意到對於[l,r],[l,l+2^x-1],[r-2^x+1,r]並起來是[l,r] 
}

int main()
{
    n=read(),m=read();
    rep(i,1,n)  a[i]=read();
    rep(i,1,n)  st[i][0]=a[i];
    rep(i,1,18) 
    {
        for(int j=1;j+(1<<i)-1<=n;j++)
        {
            st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
            //ST[j][i]爲從j開始的長度爲2^i的區間的最大值 
//顯然[j,j+2^i)=[j,j+2^(i-1))+[j+2^(i-1),j+2^i)=max(ST[i-1][j],ST[i-1][j+2^(i-1)])
        }
    }
    for(int i=1;(1<<i)<100001;i++) Log[1<<i]=i;
    for(int i=1;i<100001;i++) 
    {
        if(Log[i]==0) Log[i]=Log[i-1]; 
        //令Log[x]爲比x小的最大的2^y 
    }
    for(int i=1;i<=m;i++)
    {
        int x,y;
        x=read(),y=read();
        printf("%d\n",find(x,y));
    }
    return 0;
}
相關文章
相關標籤/搜索