poj2823 Sliding Windows(单调队列果题)

题意:

给出n,m接下来n个数。要求第一行输出该序列从左到右每连续m个数中最小的数,共n-m+1个数。第二行要求输出该序列从左到右每连续
m个数中最大的数,共n-m+1个数。

思路:

简单的单调队列的应用,两个问题共性,就说一个。用一个队列q[...]来存最值,因为区间从左到右的滑动过程中,
必然左边不满足距离条件的数需要出队列pos - q[head].pos >= m,也就是超出了询问区间,而且这个值删除
后不会影响后面的区间询问。那么当前位置的值a[pos]要添加到队列中去,当q[tail-1].value < a[i]时,
队列尾部的元素就没存在的必要了,tail--就直接删掉。

code:

const int maxn = 1e6 + 10;
struct node {
    int pos, value;
    node() {}
    node(int pos,int value) {
        this->pos = pos;
        this->value = value;
    }
}p[maxn];
int a[maxn];
int n, m;
void get_max() {
    int head = 0, tail = 0;
    for (int i = 1;i <= n;++i) {
        while(head < tail && i - p[head].pos >= m) head++;
        while(head < tail && a[i] > p[tail - 1].value) tail--;
        p[tail++] = node(i, a[i]);
        if (i >= m) printf("%d%c", p[head].value,i==n?'\n':' '); 
    }
}
void get_min() {
    int head = 0, tail = 0;
    for (int i = 1;i <= n;++i) {
        while(head < tail && i - p[head].pos >= m) head++;
        while(head < tail && a[i] < p[tail - 1].value) tail--;
        p[tail++] = node(i, a[i]);
        if (i >= m) printf("%d%c", p[head].value,i==n?'\n':' ');
    }
}
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    while(scanf("%d %d", &n, &m) != EOF) {
        for (int i = 1;i <= n;++i)
            scanf("%d", &a[i]);
        get_min();
        get_max();
    }
    return 0;
}

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