题目链接:http://poj.org/problem?id=2823
题意:给出一个长度为n的数组 a ,滑窗大小为k。滑窗每个时刻往后滑动一个,求出每个时刻窗中最大值和最小值。
思路:此为单调队列入门题。
单调队列保持如下两个性质:
- 队中保持对某一个优先级保持单调(严格?)。
- 队中的元素从队首到队尾保证时刻递增(非依次递增),即队首的元素先过期,队尾元素为新入队的元素。
维护
- 入队:保持新元素在队尾,所以新元素从队尾开始依次比较,直至满足条件,对于不满足条件的原本在队中的元素直接抛弃即可(因为新元素相比于那些删除的元素更优,且删除的元素更旧,所以删除的元素不会在之后的查询中成为答案)。
- 出队:直接取队首元素即可,即保持了队首元素先过期。
复杂度:每个元素入队出队均只有一次,所以复杂度为O(n)。
此题维护两个单调队列用来求最大值和最小值即可。
代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
const int N = 1e6 + 10;
struct Node {
int v;
int p;
Node() {}
Node(int a, int b) {
v = a;
p = b;
}
};
Node que[2][N];
struct Que {
int head, tail;
Que() {
head = 0;
tail = 0;
}
bool cmp(int t, int a, int b) {
if (t)
return a >= b;
else
return a <= b;
}
void in(int x, int t, int v, int p) {
while (head < tail && cmp(t, v, que[x][tail - 1].v))
tail--;
que[x][tail++] = Node(v, p);
}
Node out(int x) {
return que[x][head];
}
void pop(int x, int i, int w) {
while (head < tail && i - que[x][head].p >= w)
head++;
}
};
int n, k;
int main() {
while (scanf("%d%d", &n, &k) != EOF) {
Que Max, Min;
int cur = 0;
int b[N], c[N];
int x;
for (int i = 0; i < k; i++) {
scanf("%d", &x);
Max.in(0, 1, x, i);
Min.in(1, 0, x, i);
}
for (int i = k; i <= n; i++) {
b[cur] = Max.out(0).v;
c[cur++] = Min.out(1).v;
if (i == n)
break;
scanf("%d", &x);
Max.pop(0, i, k);
Max.in(0, 1, x, i);
Min.pop(1, i, k);
Min.in(1, 0, x, i);
}
for (int i = 0; i < cur; i++) {
if (i)
printf(" ");
printf("%d", c[i]);
}
printf("\n");
for (int i = 0; i < cur; i++) {
if (i)
printf(" ");
printf("%d", b[i]);
}
printf("\n");
}
return 0;
}