考虑一种类型的问题。第一次询问[L+x1,R+y1]的最小值,第二次询问[L+x2,R+y2]的最小值,,第n次询问[L+xn,R+yn]的最小值。其中有
x
i
≤
x
j
,
y
i
≤
y
j
,
i
≤
j
xi\leq xj,yi\leq yj, i\leq j
xi≤xj,yi≤yj,i≤j
最常见的一种形式就是每次询问的时候L,R都加一了。
也就这种最常见的形式写一下。
考虑到一个数存在两个价值,一个是值的大小,一个是位置。由于区间的右端点是单调的,那数肯定值的大小相同的情况下,靠在右边比较好。反过来说,靠在区间的左侧的数,肯定是值比较小的才会考虑。那么实际上,这个区间上有用的点,肯定是一个从左往右,单调递增的序列。其中最左侧的肯定是最小的,次左侧的点是次小的.
不妨令这个序列的位置,以sta[l],sta[r]的形式排列起来,那显然val[sta[l]]一定是[L,R]中val最小的,val[sta[l+1]]一定是[sta[l]+1,R]中val最小的,以此类推。
此时如果左端点+1,并且超过了最左侧的有用点,那直接把这个点丢掉就行了,就是++l,因为这种情况下,原先的val[sta[l+1]]正好就是[sta[l]+1,R]中val最小的,维持了这个序列原有的性质。
那如果此时右端点+1,只要考虑val[sta[i]]在[sta[i-1]+1,R]中最小的性质能不能拓展到[sta[i-1]+1,R+1]就可以了。那由于这个序列是单调的,假设sta[i]的最小性质可以拓展到R+1,那sta[l]…sta[i]肯定都能拓展过去了。那从sta[r]开始尝试拓展肯定是比较正常的思路。那val[sta[r]]<val[R+1]的话,就拓展成功了,那val[sta[r]]>=val[R+1]的话,根据上文的描述,sta[r]这个点就是废点了,–r丢掉即可。最后sta[++r]=R+1.
发现这个定义正好就是单调递增的单调队列的定义。
那么在左右端点单调右移的情况下,对序列的维护就完成了。这样的话,询问当前区间的最小值,输出val[sta[l]]即可。
同样如果要知道一个区间的最大值的话,维护一个单调递减的单调队列就行了。
代码就不放了.