( RMQ 区间最值问题) 给定序列 a0,⋯,an−1, m 次询问,每次询问给定 l,r,求 max{al, …,ar}。
为了解决该问题,有一个算法叫 the Method of Four Russians ,其时间复杂度为 O(n+m) ,步骤如下:
下面解决这个 ±1 RMQ 问题,“序列”指 Euler 序列:
试补全程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #include <iostream> #include <cmath> using namespace std; const int MAXN = 100000, MAXT = MAXN << 1; const int MAXL = 18, MAXB = 9, MAXC = MAXT / MAXB; struct node { int val; int dep, dfn, end; node *son[2]; // son[0], son[1] 分别表示左右儿子 } T[MAXN]; int n, t, b, c, Log2[MAXC + 1]; int Pos[(1 << (MAXB - 1)) + 5], Dif[MAXC + 1]; node *root, *A[MAXT], *Min[MAXL][MAXC]; void build() { // 建立 Cartesian 树 static node *S[MAXN + 1]; int top = 0; for (int i = 0; i < n; i++) { node *p = &T[i]; while (top && S[top]->val < p->val) ①; if (top) ②; S[++top] = p; } root = S[1]; } void DFS(node *p) { // 构建 Euler 序列 A[p->dfn = t++] = p; for (int i = 0; i < 2; i++) if (p->son[i]) { p->son[i]->dep = p->dep + 1; DFS(p->son[i]); A[t++] = p; } p->end = t - 1; } node *min(node *x, node *y) { return ③ ? x : y; } void ST_init() { b = (int)(ceil(log2(t) / 2)); c = t / b; Log2[1] = 0; for (int i = 2; i <= c; i++) Log2[i] = Log2[i >> 1] + 1; for (int i = 0; i < c; i++) { Min[0][i] = A[i * b]; for (int j = 1; j < b; j++) Min[0][i] = min(Min[0][i], A[i * b + j]); } for (int i = 1, l = 2; l <= c; i++, l <<= 1) for (int j = 0; j + l <= c; j++) Min[i][j] = min(Min[i - 1][j], Min[i - 1][j + (l >> 1)]); } void small_init() { // 块内预处理 for (int i = 0; i <= c; i++) for (int j = 1; j < b && i * b + j < t; j++) if (④) Dif[i] |= 1 << (j - 1); for (int S = 0; S < (1 << (b - 1)); S++) { int mx = 0, v = 0; for (int i = 1; i < b; i++) { ⑤; if (v < mx) { mx = v; Pos[S] = i; } } } } node *ST_query(int l, int r) { int g = Log2[r - l + 1]; return min(Min[g][l], Min[g][r - (1 << g) + 1]); } node *small_query(int l, int r) { // 块内查询 int p = l / b; int S = ⑥; return A[l + Pos[S]]; } node *query(int l, int r) { if (l > r) return query(r, l); int pl = l / b, pr = r / b; if (pl == pr) { return small_query(l, r); } else { node *s = min(small_query(l, pl * b + b - 1), small_query(pr * b, r)); if (pl + 1 <= pr - 1) s = min(s, ST_query(pl + 1, pr - 1)); return s; } } int main() { int m; cin >> n >> m; for (int i = 0; i < n; i++) cin >> T[i].val; build(); DFS(root); ST_init(); small_init(); while (m--) { int l, r; cin >> l >> r; cout << query(T[l].dfn, T[r].dfn)->val << endl; } return 0; } |