ST表实现RMQ

ST表实现RMQ

什么是RMQ?
RMQ 是英文 Range Maximum/Minimum Query 的缩写,表示区间最大(最小)值。

什么是ST表?
ST 表是用于解决 可重复贡献问题 的数据结构。
除 RMQ 以外,还有其它的“可重复贡献问题”。例如“区间按位和”、“区间按位或”、“区间 GCD”,ST 表都能高效地解决
(都是可以重复贡献问题)

对于更好的解释:OI-wiki_ST表

用ST表实现RMQ问题?
时间复杂度:\(O(n\log n)-O(1)\)
空间复杂度:\(O(n\log n)\)

『题目传送门』:洛谷P3865 ST表
题目大意:给定 \(n\) 个数,有 \(m\) 个询问,对于每个询问,你需要回答区间 \([l,r]\) 中的最大值。

关键思想:
令一个数组\(f(i,j)\)表示区间\([i,i+2^{j}-1]\)的最大值,那么显然就有\(f(i,0) = a_i\)
预处理数组关键递推式:
\(f(i,j) =\max( f(i,j-1),f(i+2^{j-1},j-1))\)
查询操作:
查询:对于每个询问 \([l,r]\) ,把它分成两部分: \(f[l,l+2^s-1]\)\(f[r-2^s+1,r]\) 。其中 \(s=\left\lfloor\log_2(r-l+1)\right\rfloor\)

代码实现

//#define judge
// Author: oceanlvr
#include <bits/stdc++.h>
using namespace std;
static int faster_iostream = []() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(NULL);
  return 0;
}();
const int logn = 21;
const int maxn = 1e6 + 10;
//令go(i,j)表示区间[i,i+2^j-1]的最大值。
int go[maxn][logn], Logn[maxn];
void pre() {
  Logn[1] = 0;
  Logn[2] = 1;
  for (int i = 3; i < maxn; i++) Logn[i] = Logn[i / 2] + 1;
}

int n, m;
int l, r;
int main() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++) cin >> go[i][0];
  pre();  //预处理Log
  for (int j = 1; j <= logn; j++) {
    for (int i = 1; i + (1 << j) - 1 <= n; i++) {
      /*
        预处理区间
        把区间分为[i,j]分为[i,i+2^{j-1}-1] [i+2^{j-1},i+2^{j}-1]
        1.即从i开始,向后跳2^{j-1}个点,右区间到i+2^{j-1}-1
        2.即从i+2^{j-1}开始,向后跳2^{j-1}个点,右区间到i+2^{j}-1
      */
      go[i][j] = max(go[i][j - 1], go[i + (1 << (j - 1))][j - 1]);
    }
  }
  for (int i = 1; i <= m; i++) {
    int x, y;
    cin >> x >> y;
    int s = Logn[y - x + 1];
    /*
      go(i,j)表示区间[i,i+2^j-1]的最大值。
      那么对于一对查询x,y,求[x,y]区间内的最大值
      对于区间长度(y - x + 1):
      有 [log(y - x + 1)]_{floor} = s
      [x][s]和[y - (1 << s) + 1][s]
    */
    cout << max(go[x][s], go[y - (1 << s) + 1][s]) << endl;
  }
  return 0;
}

posted @ 2020-03-12 16:14  AdaMeta730  阅读(181)  评论(0编辑  收藏  举报