伪入门 滑动窗口
两个队列:
单调递减 | 维护最大值 | |
---|---|---|
单调递增 | 维护最小值 |
假设目前在处理第i个元素的入队列情况,首先,这个元素肯定是要入队列的,只是直接放在队列尾部和替换掉尾部一些元素的区别。
eg.
1 | 3 | 2 | 5 | 4 |
---|
两个队列的情况分别为
两个队列 | 1 | 3 | 2 | 5 | 4 |
---|---|---|---|---|---|
维护最大值(递减序列) | 1 | 3 | 3-2 | 5 | 5-4 |
维护最小值(递增序列) | 1 | 1-3 | 1-2 | 1-2-5 | 1-2-4 |
这个队列有什么用?
以5为例子,
3-2 | 3是到5为止最大的值,2是抛弃掉3之后到5为止最大的值 |
---|
1-2 | 1是到5为止最小的值,2是抛弃掉1之后到5为止最小的值 |
---|
所以不难理解他们的递减性和递增性
所以队列里面存的是什么?
是最大值(最小值)
更详细地来说,队列头存放着可行范围的最大值,接着是 范围离开了队列头的位置后 产生的新最大值。
#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin \
ios_base::sync_with_stdio(0); \
cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int N=1e5+10;
int q_max[N],q_min[N];
//max维护最大值 递减
int a[N];
int n,m,k;
//m<= val <=k
int main()
{
while(~scanf("%d%d%d",&n,&m,&k)){
int tmp=0,ans=0;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
int h1=0,t1=0,h2=0,t2=0;
for(int i=1;i<=n;i++){
//真正的值是尾部-1
while(h1<t1 && a[q_max[t1-1]] < a[i]) //相同值留在里面
t1--;
while(h2<t2 && a[q_min[t2-1]] > a[i])
t2--;
q_max[t1++]=q_min[t2++]=i;
//找到要抛弃的最值(最大或最小值,因为改变一个就改变了他们的差值)
//也可能不抛弃任何一个,tmp值不变。
while(h1<t1&&h2<t2 && a[q_max[h1]]-a[q_min[h2]]>k)
//找哪个最值在前面,决定不要哪个
if(q_max[h1]<q_min[h2])
tmp=q_max[h1++];
else tmp=q_min[h2++];
if(h1<t1&&h2<t2 && a[q_max[h1]]-a[q_min[h2]] >= m)
ans=max(ans,i-tmp);
}
printf("%d\n",ans);
}
return 0;
}