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]);
}

 

转载于:https://www.cnblogs.com/dongdong25800/p/11112630.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值