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; }