POJ 2823 Sliding Window 单调队列

题意很明显,注意用C++提交,不然会超时。

说说我对单调队列的理解吧。

其实就是每次都在队头保留了ans。就是每次你想知道第i个位置的答案,每次取出队头元素就OK了。

然后就是怎么维护了。

例如要求最大值,那么,队头应该是一个最大值的。所以这个队列是单调递减的,每次插入a[i]的时候,维护它单调递减就OK,同时可以把它插入的这个位置后面的值删除了,是没用了。因为a[i]比他们大,而且比他们新。

关键就是这个新了。

应该这些元素不在这个窗口的话,那些就属于废弃元素,废弃元素不能被选择,所以队列有第二个参数。id。保留队头元素在数组a[i]的pos。那么当对头的id == i - k的时候。它就是废弃的了。然后把head++即可。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
int n,k;
const int maxn = 1e6 + 20;
int a[maxn];
struct node {
    int val,id;
    node () {}
    node (int vv,int ii) : val(vv), id(ii) {}
}que[maxn];
int ans_min[maxn];
int ans_max[maxn];
void work ()
{
    int lenmin = 0, lenmax = 0;
    scanf ("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) {
        scanf ("%d", a + i);
    }
//    if (k > n) {
//        while (1);
//    }
    que[1].val = a[1];
    que[1].id = 1;
    int head = 1, tail = 1;
    for (int i = 2; i <= k; ++i) { //开始预处理
        while (tail >= head && a[i] >= que[tail].val) --tail;
        ++tail;
        que[tail].val = a[i];
        que[tail].id = i;
    }
    ans_max[++lenmax] = que[head].val;
    for (int i = k + 1; i <= n; ++i) {
        while (tail >= head && a[i] >= que[tail].val) --tail;
        ++tail;
        que[tail].val = a[i]; que[tail].id = i;
        while (head <= tail && que[head].id == i - k) ++head;
        ans_max[++lenmax] = que[head].val;
    }

    head = tail = 1;
    que[tail].val = a[1];
    que[tail].id = 1;
    for (int i = 2; i <= k; ++i) {
        while (tail >= head && a[i] <= que[tail].val) --tail;
        ++tail;
        que[tail].val = a[i];
        que[tail].id = i;
    }
    ans_min[++lenmin] = que[head].val;
    for (int i = k + 1; i <= n; ++i) {
       while (tail >= head && a[i] <= que[tail].val) --tail;
       ++tail;
       que[tail].val = a[i]; que[tail].id = i;
       while (head <= tail && que[head].id == i - k) ++head;
       ans_min[++lenmin] = que[head].val; //每次取队头就是ans
    }
    for (int i = 1; i <= lenmin; ++i) {
        printf ("%d ", ans_min[i]);
    }
    printf ("
");
    for (int i = 1; i <= lenmax; ++i) {
        printf ("%d ", ans_max[i]);
    }
    printf ("
");
    return ;
}

int main()
{
#ifdef local
    freopen("data.txt","r",stdin);
#endif
    work ();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/liuweimingcprogram/p/5819448.html