在打各種acm比賽時,經常都會出現與區間有關的題目,有的是直接要求求解區間問題,有的是需要巢狀進其它演算法作為優化手段出現。
很常見的區間問題有區間查詢,區間最值等。有的是需要單次查詢,有的需要多次查詢。
假如給定乙個陣列,要求多次查詢給定區間的最大值,你會怎麼做?
rmq,全名即區間最大值/最小值查詢(range minimum/maximum query)。
下面就是乙個模板rmq題。
給定乙個長度為 n 的數列,和 m 次詢問,求出每一次詢問的區間內數字的最大值。
洛谷(p3865 st表)
最直接的方法是直接使用for迴圈遍歷區間輸出最大值。
單次查詢可以這樣,但面對m次查詢,就意味著你需要遍歷m個區間多次,最高複雜度可達o(n*m),暴力解題需要慎重。
既然暴力不行,那麼就使用有點技巧的方法。
區間最值可以使用線段樹,但使用線段樹最合適的地方是陣列在動態變化的地方(後面博文介紹),而對於靜態陣列的查詢,則可以使用st表解決。這裡介紹用st表解決靜態區間查詢問題,st表預處理的複雜度為o(nlogn),查詢複雜度為o(1)。
st表的主體是乙個二維陣列 st[i][j] ,表示所需查詢陣列的從i到i+2j-1間的最值。例如: st[2][3] 表示第2個數到第7個數的最大值。 st演算法的思想本質是動態規劃。這裡用s表示查詢陣列。
預處理對於陣列s,可以把其劃分為兩部分(a和b),那麼陣列s的最大值則是a的最大值或是b的最大值,取他們間最大的。
所以對於每乙個st陣列表示的區間,可以拆分成兩部分,
狀態轉移方程為:st[ i ][ j ] = max, (《為位運算, 1
劃分的區間為 ( i, i+2j ) -> ( i , i+2j-1 ) + ( i+2j-1 , i+2j-1+ 2j-1 )
當j=0時,20=1,st[i][0] = s[i]。
void
init()
查詢st表建好後就要進行查詢了,st表裡面包含的就是乙個區間最值的資訊,所以查詢時則只需要通過給定區間(l,r)對st表進行查詢即可。
那麼查詢區間 (l,r) 該如何進行操作呢。由於st[i][j]是表示區間(i,i+2j),所以需要先了解(l,r)區間的長度, l = r-l+1,化為指數用k表示,k=log l 。
這時候只需要找到對應的st表的區間, 因為 l 一般來說不會剛好為 2的某個次方,或者說 由於log l 是向下取整的, 2k一般會小於l,所以要確保取到正確的區間最值,可以在(l,r)的兩頭取, 取 (l,l+2k) 與 (r-2k+1,r) 區間的最值,這樣雖然包含了重複部分,但不會影響結果。
所以ans = max
//初始化log陣列 計算log時直接查詢
int log[n+7]
;void
getlog()
上面例題給出**:
#include
#define max_n 100007
#define max_m 25
// 2^25 > 100007
using
namespace std;
int s[max_n]
,log[max_n]
;int st[max_n]
[max_m]
;int n,m;
void
init()
void
getlog()
intquery
(int l,
int r)
//這裡是快讀
inline
intread()
while
(isdigit
(ch)
)return x*f;
}int
main()
return0;
}
rmq ST演算法(矩陣最值)
已知某矩陣中的值已經確定,需求矩陣中某個小矩陣的最值 st演算法 我們可以將每一行看作一維的rmq maxx i j k 表示 第i行 j,j 1模板 include include include using namespace std const int n 1e3 7 const int in...
RMQ 區間最值查詢演算法
rmq range minimum maximum query 對於長度為n的數列a,回答若干詢問rmq a,i,j i,j n 返回數列a中下標在i,j裡的最小 大 值。主要方法 樸素 即搜尋 複雜度為o n 線段樹能在對數時間內在陣列區間上進行更新與查詢。預處理 o n 查詢 o logn 定義...
RMQ問題(區間最值查詢)
有一類問題被稱作區間最值問題,描述的是,給定 n 個元素,需要查詢下標位於 p q 之間的最大 小值。首先確定,針對每一次查詢,肯定是不能動態求最值的,因為每次都要計算,可能造成比較多的時間耗費。有 一種比較好的解決辦法是,先得到所有結果,在查詢時直接取出結果。這樣,就需要一種資料結構,能夠覆蓋所有...