注:本文的确是浅谈,因为觉得不难 -.-
在我们求解 RMQ (区间最大(小)值)的时候,如果没有修改操作(就是离线),那么 ST 算法是很好的选择
空间按复杂度 \(O(n \log n)\) ,时间复杂是预处理的 \(O(n\log n)\) 和 查询的 \(O(1)\),其实用到的思想是 dp 和倍增
倍增的思想就是通过 2 的幂次来增快枚举,其实就是一个小dp。
定义
\(f[i][j]\) 表示 在 \(i\) 下标开始长度为 \(2^j\) 的区间了的最大(小)值
方程
\[f[i][j] = \max or \min(f[i][j - 1],f[i + 2 ^{j - 1}][j - 1])
\]
所求
假设查询区间 \([l,r]\) 的 RMQ 那么有 \(ans = \max or \min (f[l][\log_2 (r - l + 1)], f[r- 2^{\log_2 (r-l + 1)} + 1][\log_2(r - l + 1)])\)
于是一个简单的 dp 就可以完成。确实没什么好说的
#define _CRT_SECURE_NO_WARNINS #include <bits/stdc++.h> using namespace std; template <typename T> inline T read() { T x = 0; char ch = getchar(); bool f = 0; while(ch < '0' || ch > '9') { f = (ch == '-'); ch = getchar(); } while(ch <= '9' && ch >= '0') { x = (x << 1) + (x << 3) + (ch - '0'); ch = getchar(); } return f? -x : x; } template <typename T> void put(T x) { if(x < 0) { x = -x; putchar('-'); } if(x < 10) { putchar(x + 48); return; } put(x / 10); putchar(x % 10 + 48); return ; } const int Maxn = 1e5 + 11; int n, q, f[Maxn][18], l, r, bin[22]; inline int query(int r, int l) { int k = log2(r - l + 1); return max(f[l][k], f[r - (1 << k) + 1][k]); } int main() { n = read <int> (); q = read <int> (); for(int i = 1; i <= n; ++i) f[i][0] = read <int> (); int tmp1 = log2(n); for(int i = 1; i <= tmp1; ++i) { int tmp = 1 << i; for(int j = 1; j <= n - tmp + 1; ++j) f[j][i] = max(f[j][i - 1], f[j + tmp / 2][i - 1]); } while(q--) { put(query(read <int> (), read <int> ())); putchar('\n'); } return 0; }
据说有一种求 RMQ 的方法可以做到 \(O(n)\) 预处理,\(O(1)\) 查询,而且支持在线,好像叫约束 RMQ......QAQ
来源:https://www.cnblogs.com/zhltao/p/12598655.html