单调队列学习:
应用更新区间内最大值(最小值)
队列中存储的元素是严格递减的(存储最大值时)
举一个例子:n=9,k=3;(k是指区间长度为k时)
7 5 3 1 9 8 4 6 2
队列的插入和删除何时进行
i=1 时 { (7,1)} //存储的每个元子是(数值,脚标)
i=2 时 { (7,1),(5,2)}
i=3 时 { (7,1),(5,2),(3,3)} //插入元素比队尾元素小,直接插入队尾
i=4 时 { (5,2),(3,3),(1,4)} //当差入队尾后,队列维护的脚标范围大于k删除队首元子直至小于等于k
i=5 时 { (9,5)} //当插入元子数值大于队尾元素删除队尾,直至队尾大于插入元子数值or队列为空为止
i=6 时 { (9,5),(8,6)}
i=7 时 { (9,5),(8,6),(4,7)}
i=8 时 { (8,6),(6,8)}
i=9 时 { (6,8),(2,9)}
所以任意时刻队首元素都是区间最大值
/**
HDU 3530 Subsequence
单调队列学习:
题意:在一个序列中找到最长的连续序列
max-min大于等于m小于等于k的长度
用单调队列,存储一段区间的最大值和最小值
尽量让队列处理范围最大(满足约定条件下的)
*/
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100005
using namespace std;
int a[maxn];
int q1[maxn],q2[maxn]; //两个单调队列,分别存储最大值和最小值
int head1,head2,rear1,rear2;//两个队列的头尾节点
int main(){
int n,m,k;
while(~scanf("%d%d%d",&n,&m,&k)){
int minl=1,ans=0;
head1=head2=rear1=rear2=1;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
while(head1<rear1&&a[q1[rear1-1]]<a[i]) rear1--;
while(head2<rear2&&a[q2[rear2-1]]>a[i]) rear2--;
q1[rear1++]=i;
q2[rear2++]=i;
//找到最小的队列左边侧,且满足区间最大值和区间最小值之差小于等于k
while(head1<rear1&&head2<rear2&&a[q1[head1]]-a[q2[head2]]>k){
if(q1[head1]<q2[head2]) minl=q1[head1++]+1;
else minl=q2[head2++]+1;
}
//如果满足区间最大值和区间最小值之差大于等于m,更新结果
if(head1<rear1&&head2<rear2&&a[q1[head1]]-a[q2[head2]]>=m)
ans=max(ans,i-minl+1);
}
printf("%d\n",ans);
}
return 0;
}