RMQ(Range Minimum/Maximum Query),即區間最值查詢,是指這樣一個問題:對於長度爲n的數列A,回答若干次詢問RMQ(i,j),返回數列A中下標在區間[i,j]中的最小/大值。ios
這個有不少算法:這裏介紹一種比較高效的ST算法解決這個問題。ST(Sparse Table)算法能夠在O(nlogn)時間內進行預處理,而後在O(1)時間內回答每一個查詢。算法
令dp(i,j)表示從 i 開始的,長度爲 2^j 的一段中元素的最小值,便可以遞推出dp(i,j)=min(dp(i,j-1),dp(i+2^(j-1) , j-1))。數組
代碼:spa
void ST(int n) { for (int i = 1; i <= n; i++) dp[i][0] = A[i]; for (int j = 1; (1 << j) <= n; j++) { for (int i = 1; i + (1 << j) - 1 <= n; i++) { dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); } } } int RMQ(int l, int r) { int k = 0; while ((1 << (k + 1)) <= r - l + 1) k++; return max(dp[l][k], dp[r - (1 << k) + 1][k]);//int k=(int)(log(double(R-L+1))/log(2.0)); }
查詢是把區間分兩塊,比較得結果。.net
題目:點這裏。code
題意:給出一個非降序的整數數組,你的任務是對於一系列詢問,回答區間內出現最多的值的次數。blog
分析: 非降序,就是說相同的數會連續出現,即就能夠對其分塊,相同的數爲一塊,記錄塊的長度,左右節點。而後就能夠分紅三部分,L在的塊,R在的塊,中間的全部塊,找出中間的最長塊,L,R 在的塊的殘缺值比較,就能夠了,中間的找最長塊就用ST算法。ci
#include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<algorithm> #include<iostream> using namespace std; const int max_=1e5+5; int dp[max_][25];//RMQ的數組 int a[max_];//原數組。 int coun[max_];//分段數組 using namespace std; void RMQ_init(int t)//初始化+遞推 { for(int i=1;i<t;i++) dp[i][0]=coun[i]; for(int j=1;(1<<j)<t;j++) for(int i=1;i+(1<<j)-1<t;i++) { dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);//int k=(int)(log(double(R-L+1))/log(2.0)); } } int RMQ_Q(int l,int r)//RMQ的查詢 { if(l>r) return 0;//中間這塊爲0。 else { int k=0; while((1<<k+1)<=r-l+1)k++; return max(dp[l][k],dp[r-(1<<k)+1][k]); } } int main() { int n; while(cin>>n) { if(n==0) break; int m; int right[max_],left[max_],num[max_];//每一個段的左右端點,編號。 int a[max_]; cin>>m; for(int i=1;i<=n;i++) { cin>>a[i]; } int k=1,l=1,t=1;//,每段長度,段數 for(int i=1;i<=n;i++) { num[i]=t;//編號 if(a[i]==a[i+1]) { k++;//長度+1; } else { right[t]=i;//更新右端點 left[t]=l;//更新左端點 l=i+1; coun[t]=k;//記錄段的長度 k=1; t=t+1; } } // cout<<t<<endl; RMQ_init(t); while(m--) { int l,r; cin>>l>>r; if(num[l]==num[r])//在同一塊時。 { cout<<r-l+1<<endl; continue; } else//分三塊。 { int L=num[l]+1; int R=num[r]-1; int temp=RMQ_Q(L,R); int res=max(right[L-1]-l+1,max(temp,r-left[R+1]+1));//三塊比較。 cout<<res<<endl; } } } }超時,要改爲scanf 和printf……