问题描述
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)));
else
return 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]);
}
}
}
}