RMQ

RMQ(问题)

一. 提出问题

数列区间最大值

问题描述

输入一串数字,给你 \(M\) 个询问,每次询问就给你两个数字 \(X, Y\),要求你说出 \(X\)\(Y\) 这段区间内的最大数。

二. 思路

这一类问题有如下特点:

  1. 求区间的最值问题(min/max
  2. 数列中的元素不变(静态)

对于满足以上两个条件的问题,我们可以考虑采用倍增的策略进行解决,该问题称为 \(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 数组

  1. \(f[i][0] = a[i]\)
  2. \(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\)

  1. 可以直接调用函数 \(floor(log2(x))\),稍微性能会低一些。

  2. 自己建一个数组进行初始化,需要时直接调用数组值,速度更快。

    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]值大于等于xi位置,但是注意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]);
posted @ 2025-01-24 11:18  飞花阁  阅读(34)  评论(0)    收藏  举报
//雪花飘落效果