Loading

P3512 [POI2010]PIL-Pilots 单调队列

P3512 [POI2010]PIL-Pilots 单调队列

链接

限制与最大值最小值有关,所以我们考虑维护最大值最小值。

可以用双指针,但同时需要维护最大值最小值出现次数,但我们并维护不了任意区间内的最大值最小值。

考虑单调队列。

因为单调队列只能维护一个最值,所以我们开两个队列,一个维护最大值,一个维护最小值。

\(last\) 维护最左边合法位置的前一个是多少。

然后每当遇见不合法状态,我们就更新答案。
遇见不合法状态时,显然两个队列中肯定有一个队列只有一个元素,我们不断删除另一个队列的对头知道符合题目要求,然后更新 \(last\) 即可。

时间复杂度 \(O(n)\)
代码:

#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 3000100
#define M number
using namespace std;

const int INF=0x3f3f3f3f;

template<typename T> inline void read(T &x) {
    x=0; int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    x*=f;
}

ll n,k,a[N],qmin[N],lmin,rmin,ans,last,qmax[N],lmax,rmax;

int main(){
    read(k);read(n);
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++){
        while(lmax<rmax&&a[qmax[rmax]]<a[i]) rmax--;
        while(lmin<rmin&&a[qmin[rmin]]>a[i]) rmin--;
        qmax[++rmax]=i;qmin[++rmin]=i;
        if(a[qmax[lmax+1]]-a[qmin[lmin+1]]>k){
            ans=max(ans,i-1-last);
            if(lmax+1==rmax){
                while(a[i]-a[qmin[lmin+1]]>k) lmin++;last=qmin[lmin];
            }
            if(lmin+1==rmin){
                while(a[qmax[lmax+1]]-a[i]>k) lmax++;last=qmax[lmax];
            }
        }
    }
    ans=max(n-last,ans);
    printf("%lld\n",ans);
    return 0;
}
posted @ 2021-07-02 10:15  hyl天梦  阅读(72)  评论(0编辑  收藏  举报