簡單說就是求區間最值問題,若是簡單的單次詢問或者是區間長度很短的詢問,可以用暴力的方法來實現,但面對大資料的時候此方法必然超時,這裡介紹o(nlogn)預處理,o(1)查詢的st演算法。
st的高效在於o(nlogn)的時間預處理,o(1)的時間來查詢。其主要思想就是將所求的區間化為兩個小區間,這兩個區間的長度正好是2的k次冪,總長度正好覆蓋[l,r],得到的結果就是所求答案。
首先要清楚為什麼是分成兩段,而不是3段,4段,首先分成兩段的話是好寫的,比那些處理3段以及n段畢竟簡單。在logn的時間複雜度下,以2為底或者以其他數為底的話,時間複雜度差距也不是那麼明顯,所以選擇了分成兩段,便於位運算以及其他方面的簡便操作。
首先確定dp[i,j]表示以第i個數開始,長度為2^j的區間長度的區間最值。
易知dp[i][0] = s[i].即表示以i為起點,長度為1的區間的最值就是當前的數值。
然後可以考慮從當前乙個點,以2的指數倍向一側擴充套件,可以得到以當前點為起點,延申到邊界的陣列最值。
考慮o(nlogn)的時間複雜度,即以當前點為起始點,向右側開始維護最值,從2^1開始,因為2^k一定是偶數,所以一定可以將2^k拆分為兩個2^(k-1),即將區間[l,r]分為[l,l+2^(k-1)-1]跟[l+2^(k-1),r],將區間長度從小到大開始列舉,這樣一定可以得到以當前起點一直到n的的每乙個區間段內的最大值。
ll maxx[n][20],minn[n][20],n,s[n];
void init()
}
對於當前區間[l,r],如何表示為以某個點為起點,長度是2^k的區間。
取k=[log2(j-i+1)],則有:rmq(i, j) = max(dp[i,k], dp[j-2^k+1,k])。
考慮k的取值問題,k一定可以將整個區間都覆蓋嗎?
[l,r]分成2份,一部分是[l,i+2^(k-1)-1],一部分是[j-2^(k-1)+1,r],若是要完成覆蓋,則應該有j-2^(k-1)+1 <= i+2^(k-1)-1,移項合併同類項得到2^k >= j-i+1,可以驗證上述k取值是成立的。
分成兩個區間後,在兩個區間取最值就可以了。
ll rmq_min(ll l,ll r)
ll fpow(ll n,ll k)return r;}
ll maxx[n][20],minn[n][20],n,s[n];
void init()
}ll rmq_min(ll l,ll r)
ll rmq_max(ll l,ll r)
int main()
return 0;
}
RMQ問題 ST演算法
rmq問題 rmq問題是指求區間最值的問題。rmq演算法 st演算法 時間複雜度 預處理o nlogn 查詢o 1 以求最大值為例,設d i,j 表示 i,i 2 j 1 這個區間內的最大值,那麼在詢問到 a,b 區間的最大值時答案就是max d a,k d b 2 k 1,k 其中k是滿足2 k ...
RMQ問題的ST演算法
st sparse table 演算法的基本思想是,預先計算從起點a i 開始長度為2的j次方 j 0,1.logn 的區間的最小值,然後在查詢時將任何乙個區間a i.j 劃分為兩個預處理好的可能重疊的區間,取這兩個重疊區間的最小值。在預處理階段,從起點a i 開始,任何乙個長度為2 j的區間都可以...
RMQ問題的ST演算法
st sparse table 演算法的基本思想是,預先計算從起點a i 開始長度為2的j次方 j 0,1.logn 的區間的最小值,然後在查詢時將任何乙個區間a i.j 劃分為兩個預處理好的可能重疊的區間,取這兩個重疊區間的最小值。在預處理階段,從起點a i 開始,任何乙個長度為2 j的區間都可以...