問題描述
範圍最小化問題(Range Minimum Query,RMQ)。給出一個 n
個元素的數組 ,設計一個數據結構,支持查詢 Query(L, R):
計算 。
解題報告
令 表示從 開始的,長度爲 的一段元素中的最小值,則可以用遞推的方式計算 。
爲什麼 dp[i][j]
表示的是 從 開始的,長度爲 的一段元素中最小值呢?
如果這樣的話,就需要在三個區間中找最小值,一方面狀態轉移方程不好寫,另一方面,時間複雜度和空間複雜度並沒有提升多少,所以是 。
注意到 ,因此 d
數組的元素個數不超過 ,而每一項都可以在常數時間計算完畢,故總時間爲
查詢操作很簡單,令 k
爲滿足 的最大整數,則以 開頭、以 結尾的兩個長度爲 的區間合起來覆蓋了查詢區間 。由於是取最小值,有些元素重複考慮了幾遍也沒有關係。
實現代碼
- 預處理
void RMQ_INIT(const vector<int>&A){
int n= A.size();
for(int i=0;i<n;i++)dp[i][0]=A[i];
for(int j=1;(1<<j)<=n;j++){
for(int i=0;i+(1<<j)-1<n;i++)
dp[i][j]=min(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 min(d[l][k], d[r-(1<<k)+1][k])
}
參考資料
[1] 算法競賽·入門經典·訓練指南 P197.