[单调队列] POJ2823

来源:互联网 发布:mac foxmail 邮件备份 编辑:程序博客网 时间:2024/05/21 04:18

找出范围内的最大和最小


第一次接触单调队列(保证队列单调性)

放一下方法(因为明天一定会忘光光的hhh)

开始很不理解为什么队列要把比新插入的数小的数全部删除

但这道题只要最大值就没追究了

也是能保持头部的index永远是最小的一个关键

判断改成head<=end 后就不是WA了

但g++还是TLE,C++是AC

参考:http://blog.csdn.net/justmeh/article/details/5844650

假设数列为:8,7,12,5,16,9,17,2,4,6.N=10,k=3.

那么我们构造一个长度为3的单调递减队列:

首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:

0:插入8,队列为:(8,0)

1:插入7,队列为:(8,0),(7,1)

2:插入12,队列为:(12,2)

3:插入5,队列为:(12,2),(5,3)

4:插入16,队列为:(16,4)

5:插入9,队列为:(16,4),(9,5)


1.首先看插入元素:为了保证队列的递减性,我们在插入元素v的时候,要将队尾的元素和v比较,如果队尾的元素不大于v,则删除队尾的元素,然后继续将新的队尾的元素与v比较,直到队尾的元素大于v,这个时候我们才将v插入到队尾。


2.队尾的删除刚刚已经说了,那么队首的元素什么时候删除呢?由于我们只需要保存i的前k-1个元素中的最大值,所以当队首的元素的索引或下标小于i-k+1的时候,就说明队首的元素对于求f(i)已经没有意义了,因为它已经不在窗里面了。所以当index[队首元素]<i-k+1时,将队首元素删除。


#include <cstdio>#include <cstring>#include <iostream>#define N 3500000using namespace std;int n, k;int Num[ N ]; //输入struct Node {        int val, idx;} Que[ N ];void GetMax () {        memset ( Que, 0, sizeof ( Que ) );        int head = 0; //保存头部位置        int end = -1; //保存尾部位置        for ( int i = 1; i <= n; i++ ) {                Node tmp;                tmp.val = Num[ i ];                tmp.idx = i;                while ( head <= end && Que[ end ].val <= Num[ i ] ) // 1.去掉尾部比新加入元素小的                        end--;                Que[ ++end ] = tmp;                while ( head <= end && Que[ head ].idx < i - k + 1 ) // 2.去掉头部index超过范围的                        head++;                if ( i >= k ) {                        if ( i != k )                                printf ( " " );                        printf ( "%d", Que[ head ] );                }        }        printf ( "\n" );}void GetMin () {        memset ( Que, 0, sizeof ( Que ) );        int head = 0;        int end = -1;        for ( int i = 1; i <= n; i++ ) {                Node tmp;                tmp.val = Num[ i ];                tmp.idx = i;                while ( head <= end && Que[ end ].val >= Num[ i ] )                        end--;                Que[ ++end ] = tmp;                while ( head <= end && Que[ head ].idx < i - k + 1 )                        head++;                if ( i >= k ) {                        if ( i != k )                                printf ( " " );                        printf ( "%d", Que[ head ] );                }        }        printf ( "\n" );}int main () {        while ( cin >> n && cin >> k ) {                for ( int j = 1; j <= n; j++ )                        scanf ( "%d", &Num[ j ] );                GetMin ();                GetMax ();        }        return 0;}