[BZOJ2096][Poi2010]Pilots(单调队列)

题目描述

传送门

题解

由于满足r是随着l单调的,那么两个指针扫一遍即可。
扫的过程中要判断扩展的r是否合法,可以用单调队列维护处l~r这一段的最大值和最小值,然后随便判断一下。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 3000005

int k,n,l,r,lmax,rmax,lmin,rmin,ans;
int a[N],qmax[N],qmin[N];
struct hp{int Max,Min;};

void push(int id)
{
    while (lmax<rmax&&a[qmax[rmax]]<=a[id]) --rmax;
    qmax[++rmax]=id;
    while (lmin<rmin&&a[qmin[rmin]]>=a[id]) --rmin;
    qmin[++rmin]=id;
}
hp pop(int id)
{
    while (lmax<rmax&&qmax[lmax+1]<id) ++lmax;
    int Max=a[qmax[lmax+1]];
    while (lmin<rmin&&qmin[lmin+1]<id) ++lmin;
    int Min=a[qmin[lmin+1]];
    return (hp){Max,Min};
}
int main()
{
    scanf("%d%d",&k,&n);
    for (int i=1;i<=n;++i) scanf("%d",&a[i]);
    l=r=1;lmax=rmax=lmin=rmin=0;push(l);
    while (l<=n)
    {
        if (l>r)
        {
            r=l;lmax=rmax=lmin=rmin=0;push(l);
        }
        while (r<n)
        {
            hp now=pop(l);
            if (a[r+1]>now.Max)
                {if (a[r+1]-now.Min>k) break;}
            else if (a[r+1]<now.Min)
                {if (now.Max-a[r+1]>k) break;}
            ++r;push(r);
        }
        ans=max(ans,r-l+1);
        ++l;
    }
    printf("%d\n",ans);
}

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值