ST表实现RMQ

ST表实现RMQ

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

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

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

用ST表实现RMQ问题?
时间复杂度:(O(nlog n)-O(1))
空间复杂度:(O(nlog 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=leftlfloorlog_2(r-l+1) ight floor)

代码实现

//#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;
}

原文地址:https://www.cnblogs.com/adameta/p/12470003.html