RMQ区间最值问题)给定序列a0, … ,an-1,和m次询问,每次询问给定l,r,求max {al, … ,ar}
为了解决该问题,有一个算法叫theMethodofFourRussians,其时间复杂度为O(n+m),步骤如下:
·建立 Cartesian(笛卡尔)树,将问题转化为树上的 LCA(最近公共祖先)问题。
·对于 LCA问题,可以考虑其 Euler序(即按照 DFS过程,经过所有点,环游回根的序列),即求 Euler序列上两点间一个新的 RMQ问题。
·注意新的问题为 ±1RMQ,即相邻两点的深度差一定为 1。
下面解决这个 ±1RMQ问题,“序列”指 Euler序列:
·设t为 Euler序列长度。取b=[]。将序列每b个分为一大块, 使用 ST表(倍增表)处理大块间的 RMQ问题,复杂度O(logt)=O(n)。
·(重点)对于一个块内的 RMQ问题,也需要O(1) 的算法。由于差分数组 2b-1种,可以预处理出所有情况下的最值位置,预处理复杂度O(b2b),不超过O(n
)。
·最终,对于一个查询,可以转化为中间整的大块的 RMQ问题,以及两端块内的 RMQ问题。
试补全程序。
#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; intdep, 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; }
x->dep < y->dep