//poj 2823 Sliding Window
//单调队列
//以下是复制别人的思路的,自己写的代码过不了,这代码也是模仿别人的
//这题还可以用单调队列进行求解。开两个队列,一个维护最大值,
//一个维护最小值。下面叙述最大队列,最小队列的方法类似。
//最大队列保证队列中各个元素大小单调递减(注意,不是单调不上升),
//同时每个元素的下标单调递增。这样便保证队首元素最大,而且更新的
//时候队首永远是当前最大。因此,这个队列需要在两头都可以进行删除,
//在队尾插入。
//维护方法:在每次插入的时候,先判断队尾元素,如果不比待插入元素
//大就删除,不断删除队尾直到队尾元素大于待插入元素或者队空。删除
//的时候,判断队首,如果队首元素下标小于当前段左边界就删除,不断
//删除队首直到队首元素下标大于等于当前段左边界(注意:这时队列肯
//定不为空),队首元素就是当前段的最优解。
#include <stdio.h>
#include <string.h>
#define N 1000005
int input()
{
char ch;
int sign = 1, num = 0;
while(ch = getchar(), ch == '\n' || ch == ' ');
if(ch == EOF)
return EOF;
if(ch == '-')
{
sign = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
num = num * 10 + ch - '0';
ch = getchar();
}
return sign * num;
}
int arr[N], mn[N], mx[N], time[N], ans[N];
int len, k;
void getMin()
{
int head = 1, tail = 0;
for(int i = 1; i <= len; ++i)
{ //删除队尾比要插入的数大的数
while(head <= tail && mn[tail] >= arr[i])
tail--;
mn[++tail] = arr[i]; //把要插入的数插入到队尾,因此
time[tail] = i; //队列后面的数肯定比前面的数晚过期
if(i >= k)
{
while(time[head] <= i - k)//注意:这里要等,eg:当i=k+1时
head++; //第一个就过期了
ans[i-k] = mn[head];
}
}
}
void getMax()
{
int head = 1, tail = 0;
for(int i = 1; i <= len; ++i)
{
while(head <= tail && mx[tail] <= arr[i])
tail--;
mx[++tail] = arr[i];
time[tail] = i;
if(i >= k)
{
while(time[head] <= i - k)
head++;
ans[i-k] = mx[head];
}
}
}
void print()
{
int end = len-k; //总的有 1+end 组 宽度为 k 的数
for(int i = 0; i <= end; ++i)
{
printf("%d", ans[i]);
if(i != end)
putchar(' ');
}
puts("");
}
int main()
{
while(scanf("%d%d", &len, &k) != EOF)
{
for(int i = 1; i <= len; ++i)
arr[i] = input();
getMin();
print();
getMax();
print();
}
return 0;
}