solution
肥肠经典的极值问题,可以使用ST表(复杂度为)或者单调队列(复杂度
)来做,这里讲一下复杂度更优的单调队列做法。
题目要求长度为k的区间极值,我们从左往右扫并且维护一个队列,队列里存放的为数字下标,并且这个队列要满足两个条件。
条件一:队列中所有位置与当前扫到的位置i之间的距离不超过k。
条件二:队列中下标对应的位置和下标均为有序的。
这样每当我们从i枚举到了i+1,我们都从队首找到与距离大于k的下标弹出去。这样就保证了条件一。
然后考虑维护条件二,我们向队列中添加元素时,需要保证这个元素所添加到的位置前的数字均大于(求最小值是为小于)当前位置的数字。那么我们考虑队尾的数字j,如果现在要添加的位置为i,那么当时,后面的位置肯定是
比
更优。所以直接将j踢出去即可。
然后就做完了。复杂度
code
/*
* @Author: wxyww
* @Date: 2020-04-02 14:27:21
* @Last Modified time: 2020-04-02 14:31:39
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 1000010;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int a[N],q[N],T,H;
int main() {
int n = read(),K = read();
for(int i = 1;i <= n;++i) a[i] = read();
H = 1;
for(int i = 1;i <= n;++i) {
while(H <= T && q[H] <= i - K) ++H;
while(H <= T && a[q[T]] > a[i]) --T;
q[++T] = i;
if(i >= K) printf("%d ",a[q[H]]);
}
puts("");
H = 1;T = 0;
for(int i = 1;i <= n;++i) {
while(H <= T && q[H] <= i - K) ++ H;
while(H <= T && a[q[T]] < a[i]) --T;
q[++T] = i;
if(i >= K) printf("%d ",a[q[H]]);
}
return 0;
} 
京公网安备 11010502036488号