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.