Luogu P1440 求m区间内的最小值

# 这题可以用RMQ(ST表)做!

由于本题数据的特殊性,需要查找的区间的元素个数大部分是一样的(除了输出的前$m$行元素个数不足$m$个的情况),我们就可以把ST表(代码中$a$数组)进行降维攻击(雾)!这样一来使用RMQ(ST表)就不会MLE了!

在时间方面,我们可以拿个变量(代码中$power$)存储$2$的$j$次方,这样就不需要每一步都进行位运算了,这样做竟把超时的一个点卡过去了……

时空问题都解决了,接下来只要和一般的RMQ(ST表)进行相同的操作就可以了。


 

但我们似乎忽略了一个问题……

就是输出的前$m$行元素个数不足$m$个时,我们要从第一个元素开始找,元素个数肯定不到$m$个。但最后因降过维,我们只能输出元素个数为$m$的区间的最小值,这下应该怎么办呢?

这时我们可以想到,区间元素个数小于$m$时是在倍增预处理的时候,这时的ST表还未定型,在中途过程中会出现我们需要的答案,所以这部分的答案要在我们倍增的过程中输出。

我们发现,倍增过程中的每一层要输出的答案个数是不同的:

1. 第一个输出肯定为$0$,因为第一个数前是没有数的;

2. 如果$m>1$,那么第二个输出肯定是第一个数,因为第二个数前面只有一个数;

3. 我们手推一下可以发现,在建ST表的过程中,编号小于等于$2 \times power$的答案可以直接输出(当然仅限于编号小于$m$的数,即元素个数不足$m$个);

4. 剩下的数就直接在ST表建好后按正常RMQ方法输出最小值就可以啦~


 

pascal代码如下:

uses math;//log2要用math库qwq
var n,m,i,j,k,l,power:longint;
a:array[0..2000000]of longint;
begin
readln(n,m);
for i:=1 to n do
read(a[i]);
writeln(0);//情况1
if m>1 then//情况2
writeln(a[1]);
k:=trunc(log2(m));
l:=2;//l为当前应输出第l个答案
power:=1;
for j:=1 to k do//建ST表
begin
power:=power*2;
for i:=1 to n-power+1 do
a[i]:=min(a[i],a[i+power div 2]);
while (l<=power*2)and(l<m) do//情况3
begin
writeln(min(a[1],a[l-power+1]));
inc(l);
end;
end;
for i:=1 to n-m do//情况4
writeln(min(a[i],a[i+m-power]),' ');
end.

 

posted @ 2018-02-07 14:07  qbwhtc  阅读(183)  评论(0编辑  收藏  举报