POJ2823 (单调队列)

 

POJ2823

题意:给n个数字,有一个大小为k的框,从左往右框数字,一共框n-k+1次,问每次框中数字的最大,最小值。

思路:可以先思考只求最大值,因为1e6的数字,维护最大堆的复杂度是nlogn,肯定超时了。我们可以想到,框每次向右移动一格,只会增加一个数字,减少一个数字,可以想到,我们要维护一个序列,

通过这个序列来更新最大值,抹除左边出去的值,这个可以想到要用单调队列来解决,我们维护一个单调递减的序列,每次新加的数字如果最小,放队尾,如果较大,就依次删队尾元素,找到它该在的位置。通过这个方式,我们使一个队列,始终有着目前的最大值。

总之,对于求最大值,维护一个递减序列,求最小值,维护一个递增序列。

 

 

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
struct note
{
    int x,y;
} q[maxn];

int minn[maxn],maxx[maxn];
int a[maxn];
int n,k;
void getmax()
{
    int head=1;
    int tail=0;
    for(int i=1; i<=k-1; i++)
    {
        while(q[tail].x<=a[i]&&head<=tail)
        {
            tail--;
        }
        q[++tail].x=a[i];
        q[tail].y=i;
    }
    for(int i=k; i<=n; i++)
    {
        while(q[tail].x<=a[i]&&head<=tail)
        {
            tail--;
        }
        q[++tail].x=a[i];
        q[tail].y=i;
        while(q[head].y<(i-k+1))
        {
            head++;
        }
        maxx[i-k+1]=q[head].x;
    }
}

void getmin()
{
    int head=1;
    int tail=0;
    for(int i=1;i<=k-1;i++)
    {
        while(a[i]<=q[tail].x&&head<=tail)
        {
            tail--;
        }
        q[++tail].x=a[i];q[tail].y=i;
    }
    for(int i=k;i<=n;i++)
    {
        while(a[i]<=q[tail].x&&head<=tail)
        {
            tail--;
        }
        q[++tail].x=a[i];q[tail].y=i;
        while(q[head].y<(i-k+1))
        {
            head++;
        }
        minn[i-k+1]=q[head].x;
    }
}
int main()
{

    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    getmax();
    getmin();
    for(int i=1; i<=n-k+1; i++)
        printf("%d ",minn[i]);
    printf("\n");
    for(int i=1;i<=n-k+1;i++)
        printf("%d ",maxx[i]);
}

 

posted @ 2019-07-01 10:19  paranoid。  阅读(572)  评论(0编辑  收藏  举报