[POJ 2823]Sliding Window[单调队列]

题目链接: [POJ 2823]Sliding Window[单调队列]

题意分析:

包含n个数字的数列,用一个长度为k的窗口移动从1开始向右移动,每次输出窗口中的最小值和最大值。分两行输出结果:最小值输出到上行,最大值输出到下行。

解题思路:

考虑每次移动窗口要进行的操作,总共有两种,增加一个数,删去一个数。考虑到需要涉及到删除操作,我们使用单调队列来进行维护。

L代表队列的左端,R代表队列的右端,以递增队列为例:

如果我们在队列中存储当前的值,那么整个删除操作会特别耗时。转换思路,考虑在队列中存放当前值的下标,而依靠值来排序。

那么队列左端第一个存储的下标,就是最小的值对应的下标。每次增加值从右端往左插入,如果队列中的那个值大于当前值,就可以直接丢弃(因为这个值出现的时间早于当前值,之后肯定不会成为最小值)。输出最小值的话,我们从左端往右端,第一个满足i - 下标 < k的值,就是我们要的满足条件的最小值。

个人感受:

存下标真是太机智了。

具体代码如下:

#include<stdio.h>

int a[1000100], q[1000100];

int main()
{
    int n, k;
    while (~scanf("%d%d", &n, &k)) {
        int l = 0, r = 0, i, j;
        for (i = 0; i < n; ++i) scanf("%d", &a[i]);
        q[r] = 0;
        for (i = 1; i < k; ++i) {
            while (r >= 0 && a[q[r]] >= a[i]) --r;
            q[++r] = i;
        }
        printf("%d", a[q[l]]);

        for (i = k; i < n; ++i) {
            while (r >= l && a[q[r]] >= a[i]) --r;
            q[++r] = i;
            while (i - q[l] >= k) ++l;
            printf(" %d", a[q[l]]);
        }
        putchar('\n');

        l = r = 0;
        q[r] = 0;
        for (i = 1; i < k; ++i) {
            while (r >= 0 && a[q[r]] <= a[i]) --r;
            q[++r] = i;
        }
        printf("%d", a[q[l]]);
        for (i = k; i < n; ++i) {
            while (r >= l && a[q[r]] <= a[i]) --r;
            q[++r] = i;
            while (i - q[l] >= k) ++l;
            printf(" %d", a[q[l]]);
        }
        putchar('\n');
    }
    return 0;
}


你可能感兴趣的:([POJ 2823]Sliding Window[单调队列])