RMQ
RMQ(问题)
一. 提出问题
问题描述
输入一串数字,给你 \(M\) 个询问,每次询问就给你两个数字 \(X, Y\),要求你说出 \(X\) 到 \(Y\) 这段区间内的最大数。
二. 思路
这一类问题有如下特点:
- 求区间的最值问题(
min/max) - 数列中的元素不变(静态)
对于满足以上两个条件的问题,我们可以考虑采用倍增的策略进行解决,该问题称为 \(RMQ(Range\; Max/Min\; Query)\) 问题,使用的数组是一种稀疏数组(\(ST\)表,\(Sparse\; Table\)),仅存入大小恰为 \(2^j\) 的区间最值。
令 f[i][j] 表示区间 \([i, i+2^j-1]\) 的最大值,其中 \(j\) 代表 \(2\) 的 \(j\) 次方,即区间所包含的元素个数。
-
当我们需要求出 \([1, 8]\) 的最大值时,直接输出 \(f[1][3]\) 即可。
-
当我们需要求出 \([3,9]\) 的最大值时,由于该区间包含 \(7\) 个数,不是 \(2\) 的整数幂,则需要将该区间拆成 \(2\) 个 \(2\) 的整数幂的集合,由它们各自的最大值再去求最大值,得出答案,即将 \([3,9]\) 拆成 \([3,6],[6,9]\) 两个长度为 \(2^2\) 的区间,答案即为 \(max(f[3][2], f[6][2])\)。
注意:两个集合的交集部分,不会对求最值问题产生影响。
-
当需要求出 \([a,b]\) 的最大值时,令 \(j=\lfloor log_2^{b-a+1}\rfloor\),答案为 \(max(f[a][j], f[b-(1<<j)+1][j])\)。
三. 如何求 f 数组
- \(f[i][0] = a[i]\)
- \(j>0,f[i][j]=max(f[i][j-1], f[i+(1<<j-1)][j-1]);\)
注意:在求的过程中,与区间DP相同,代表长度的 j 的循环必须在外层,i的循环在内层。
完整代码如下:
for (int j = 1; (1<<j) <= n; ++j)
for (int i = 1; i+(1<<j)-1 <= n; ++i)
f[i][j] = max(f[i][j-1], f[i+(1<<j-1)][j-1];
该算法的时间复杂度为 \(O(n\ log\ n)\)。
四. 如何求 \(j=\lfloor log_2^{b-a+1}\rfloor\)
-
可以直接调用函数 \(floor(log2(x))\),稍微性能会低一些。
-
自己建一个数组进行初始化,需要时直接调用数组值,速度更快。
lg[1] = 0; for (int i = 2; i <= n; ++i) lg[i] = lg[i>>1] + 1;
五、难题
问题描述
A 是某公司的 CEO,每个月都会有员工把公司的盈利数据送给 A,A 是个与众不同的怪人,A 不注重盈利还是亏本,而是喜欢研究「完美序列」:一段连续的序列满足序列中的数互不相同。
A 想知道区间 \([L,R]\) 之间最长的完美序列长度。
输入格式
第一行两个整数 \(N,M\),\(N\) 表示连续 \(N\) 个月,编号为 \(0\) 到 \(N-1\),\(M\) 表示询问的次数;
第二行 \(N\) 个整数,第 \(i\) 个数表示该公司第 \(i\) 个月的盈利值 \(a_i\);
接下来 \(M\) 行每行两个整数 \(L,R\),表示 A 询问的区间。
输出格式
输出 \(M\) 行,每行一个整数对应询问区间内的完美序列的最长长度。
思路分析
点击查看代码
- 引子
pre[i]表示以i为右端点,a[i]上一次出现的位置
则一段区间 \([x,y]\) 为完美区间,对应的 \([x,y]\) 中的每一个pre[i]均满足什么条件?
\(max\{pre[i]\} < x, x\le i\le y\)
int k = lower_bound(pre+x, pre+y+1, x) - pre;
k为 \([x,y]\) 中第一个pre[i]值大于等于x的i位置,但是注意pre[i]并不是单调的
所以我们需要将pre[i]进行一定的改造,使其满足单调性,最简单的方式就是将单点信息变为前缀信息
- 正解
令last[a[i]]为a[i]上一次出现的位置
令pre[i]为 \([1,i]\) 中last[j]的最大值,\(1\le j\le i\)
pre[i] = max(pre[i-1], last[a[i]]);
int k = lower_bound(pre+x, pre+y+1, x) - pre;
此时,可以确定 \([x,k-1]\) 一定是一个完美区间,\(ans = k - x;\)
当 \(j\ge k\) 时,\([pre[j]+1, j]\) 为一个完美区间,ans = max(ans, j-pre[j]);
令f[j][0] = j - pre[j],p = lg[y-k+1],则有ans = max{k-x, f[k][p], f[y-(1<<p)+1][p]);

浙公网安备 33010602011771号