POJ 2823 Sliding Window(单调队列)

单调队列模板题。

单调队列有两个性质:

1.数值大小单调     2.队列元素位置单调

插入查询的规则是,如果要求最小值,那么队列要从小到大排序,结果在队头。求最大值则相反。这是因为插入时要满足性质2,所以只能插在队尾,那么新元素要替换的值应该是比它大的,所以队列整体要从小到大排,才能保证大的数都在队尾一侧,实现查询最小值。

插入时替换比它大的数的理由是,对于新的数,因为位置大于老的数,从这个位置开始所有包含老的数的区间都包含新的数。如果新的数小于老的数,那么查询到的最小值永远不会是老的那个数,可以直接把他出队。


本题因为还有一个区间的限制,所以要用一个结构体记录每个元素的位置,并要用队头队尾两个指针。如果队头元素位置已经超出区间,队头要移动。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

struct node{
    int pos,v;
};

node a[1000005],q[1000005];
int hd,tl;
int N,K;
int main(){
    scanf("%d%d",&N,&K);
    for(int i=0;i<N;i++){
        scanf("%d",&a[i].v);
        a[i].pos=i;
    }
    hd=tl=0;
    q[0]=a[0];
    for(int i=1;i<K-1;i++){
        while(tl>=hd&&q[tl].v>=a[i].v) tl--;
        q[++tl]=a[i];
    }
    for(int i=0;i<N-K+1;i++){
        while(tl>=hd&&q[tl].v>=a[i+K-1].v) tl--;
        q[++tl]=a[i+K-1];
        while(q[hd].pos<i) hd++;
        printf("%d",q[hd].v);
        if(i==N-K) printf("\n");
        else printf(" ");
    }
    hd=tl=0;
    q[0]=a[0];
    for(int i=1;i<K-1;i++){
        while(tl>=hd&&q[tl].v<=a[i].v) tl--;
        q[++tl]=a[i];
    }
    for(int i=0;i<N-K+1;i++){
        while(tl>=hd&&q[tl].v<=a[i+K-1].v) tl--;
        q[++tl]=a[i+K-1];
        while(q[hd].pos<i) hd++;
        printf("%d",q[hd].v);
        if(i==N-K) printf("\n");
        else printf(" ");
    }
    return 0;
}


你可能感兴趣的:(单调队列)