问题描述
RMQ (Range Minimum/Maximum Query)问题是指:
对于长度为n的数列A,回答若干询问RMQ(A,i,j)(i,j<=n),返回数列A中下标在i,j里的最小(大)值,也就是说,RMQ问题是指求区间最值的问题。
例题
AcWing 1273. 天才的记忆 RMQ
AcWing 1270. 数列区间最大值 RMQ
AcWing 1272. 与众不同 双指针 + RMQ + 二分
方法1 线段树
很简单,不赘述了
static class Node {int l, r;int max;Node(int l, int r) {this.l = l;this.r = r;}}static int N = 200010;static Node[] tr = new Node[N * 4];static int n;static int[] a = new int[N];static void solve() {n = ni();for (int i = 1; i <= n; i++)a[i] = ni();build(1, 1, n);int m = ni();while (m-- > 0) {int l = ni(), r = ni();out.println(query(1, l, r));}}static void build(int u, int l, int r) {if (l == r) {tr[u] = new Node(l, r);tr[u].max = a[l];} else {int mid = l + r >> 1;tr[u] = new Node(l, r);build(u << 1 , l, mid);build(u << 1 | 1, mid + 1, r);pushup(u);}}static int query(int u, int l, int r) {if (l <= tr[u].l && r >= tr[u].r)return tr[u].max;else {int mid = tr[u].l + tr[u].r >> 1;int res = Integer.MIN_VALUE;if (l <= mid) res = Math.max(res, query(u << 1, l, r));if (r > mid) res = Math.max(res, query(u << 1 | 1, l, r));return res;}}static void pushup(int u) {tr[u].max = Math.max(tr[u << 1].max, tr[u << 1 | 1].max);}
方法2 Fenwick Tree
使用树状数组求解区间最值,时间复杂度为O(log2n)
思想:tr[i]维护[i - lowbit[i] + 1, i]这一段区间的最值
static final int N = 200010;static int[] tr = new int[N];static int[] a = new int[N];static int n;static void solve() {n = ni();for (int i = 1; i <= n; i++) {a[i] = ni();// modify(i, a[i]);}build();int m = ni();while (m-- > 0) {int l = ni(), r = ni();out.println(query(l, r));}}static void build() {for (int i = 1; i <= n; i++) {tr[i] = a[i];for (int j = 1; j < lowbit(i); j <<= 1)tr[i] = Math.max(tr[i], tr[i - j]);}}static int query(int l, int r) {if (l == r)return a[l];if (l == r - lowbit(r) + 1)return tr[r];else if (l < r - lowbit(r) + 1)return Math.max(tr[r], query(l, r - lowbit(r)));elsereturn Math.max(a[r], query(l, r - 1));}static int lowbit(int x) {return x & (-x);}static void modify(int idx, int x) {a[idx] = x;for (int i = idx; i <= n; i += lowbit(i)) {if (x >= tr[i])tr[i] = x;else {tr[i] = x;for (int j = 1; j < lowbot(i); j <<= 1)tr[i] = Math.max(tr[i], tr[i - j]);}}}}
