题意:
给出n,m接下来n个数。要求第一行输出该序列从左到右每连续m个数中最小的数,共n-m+1个数。第二行要求输出该序列从左到右每连续
m个数中最大的数,共n-m+1个数。
思路:
简单的单调队列的应用,两个问题共性,就说一个。用一个队列q[...]来存最值,因为区间从左到右的滑动过程中,
必然左边不满足距离条件的数需要出队列pos - q[head].pos >= m,也就是超出了询问区间,而且这个值删除
后不会影响后面的区间询问。那么当前位置的值a[pos]要添加到队列中去,当q[tail-1].value < a[i]时,
队列尾部的元素就没存在的必要了,tail--就直接删掉。
code:
const int maxn = 1e6 + 10;
struct node {
int pos, value;
node() {}
node(int pos,int value) {
this->pos = pos;
this->value = value;
}
}p[maxn];
int a[maxn];
int n, m;
void get_max() {
int head = 0, tail = 0;
for (int i = 1;i <= n;++i) {
while(head < tail && i - p[head].pos >= m) head++;
while(head < tail && a[i] > p[tail - 1].value) tail--;
p[tail++] = node(i, a[i]);
if (i >= m) printf("%d%c", p[head].value,i==n?'\n':' ');
}
}
void get_min() {
int head = 0, tail = 0;
for (int i = 1;i <= n;++i) {
while(head < tail && i - p[head].pos >= m) head++;
while(head < tail && a[i] < p[tail - 1].value) tail--;
p[tail++] = node(i, a[i]);
if (i >= m) printf("%d%c", p[head].value,i==n?'\n':' ');
}
}
int main(int argc, const char * argv[])
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(scanf("%d %d", &n, &m) != EOF) {
for (int i = 1;i <= n;++i)
scanf("%d", &a[i]);
get_min();
get_max();
}
return 0;
}