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