金典的单调队列的题目。
题目大意给你n个数和一个k(0 < k ,n < 10^6),一个长度为k的窗口在长度为为n的序列滑动,没滑动一个位置,求出这个窗口里的最小值和最大值,先输出最小值得序列,再输出最大值的序列。
n很大不能在每一个窗口中去遍历出最小值跟最大值,这里用到一个单调队列。此处只做出最小值得序列求解,最大值序列同理。
用一个单调非严格递增的队列去维护此时最小值。
<pre name="code" class="cpp">
#include <cstdio>
#define MAXN 1000007
int arr[MAXN];
int que[MAXN * 10];
int read()//快速读入
{
char ch;
int v = 0, s = 1;
while(ch = getchar(), ch == ' ' || ch == '\n' || ch == '\t');
if(ch == '-') s = -1;
else v = ch - '0';
while(ch = getchar(), ch != ' ' && ch != '\n' && ch != '\t') v = v * 10 + ch - '0';
return v * s;
}
void write(int x, char c) //快速输出
{
char ch[10], pos = 0;
if(x < 0) putchar('-');
x = x > 0? x: -x;
if(!x) putchar('0');
while(x)
{
ch[pos++] = x % 10;x /= 10;
}
while(pos)
putchar(ch[--pos] + '0');
putchar(c);
}
int main()
{
int n, k;
while(~scanf("%d%d", &n, &k))
{
if(n < k) k = n;
for(int i = 0; i < n; ++i)
arr[i] = read();
int front = 0, rear = -1;
que[++rear] = 0;
for(int i = 1; i <= n; ++i)
{
if(i >= k )
{
write(arr[que[front]], i < n? ' ': '\n');
if(i - que[front] >= k) front++;
}
while(rear >= front && arr[que[rear]] > arr[i])
rear--;
que[++rear] = i;
}
front = 0, rear = -1;
que[++rear] = 0;
for(int i = 1; i <= n; ++i)
{
if(i >= k)
{
write(arr[que[front]], i < n? ' ': '\n');
if(i - que[front] >= k) front++;
}
while(rear >= front && arr[que[rear]] < arr[i])
rear--;
que[++rear] = i;
}
}
return 0;
}