hdu 3530 单调队列最值
/** HDU 3530 单调队列的应用 题意: 给定一段序列,求出最长的一段子序列使得该子序列中最大最小只差x满足m<=x<=k。 解题思路: 建立两个单调队列分别递增和递减维护(头尾删除,只有尾可插入) Max - Min 为两个队列的队首之差while(Max-Min>K) 看哪个的队首元素比较前就移动谁的 最后求长度时,需要先记录上一次的被淘汰的最值位置last ,这样[last+1,i]即为满足条件的连续子序列了 i - last */ #include <stdio.h> #include <iostream> #include <string.h> #include <algorithm> using namespace std; const int N=100005; int q_max[N],q_min[N];//递增,递减 int a[N],n,m,k; int main() { while(~scanf("%d%d%d",&n,&m,&k)) { for(int i=1;i<=n;i++) scanf("%d",&a[i]); int head_min=0,head_max=0,tail_min=0,tail_max=0; int left1=0,left2=0; int maxx=0; for(int i=1;i<=n;i++) { while(head_min<tail_min&&a[q_min[tail_min-1]]<=a[i]) tail_min--; while(head_max<tail_max&&a[q_max[tail_max-1]]>=a[i]) tail_max--; q_max[tail_max++]=q_min[tail_min++]=i; /* printf("***%d 递减、递增***\n",i); for(int j=head_min;j<tail_min;j++) printf("%d ",a[q_min[j]]); printf("\n"); for(int j=head_max;j<tail_max;j++) printf("%d ",a[q_max[j]]); printf("\n");*/ while(a[q_min[head_min]]-a[q_max[head_max]]>k) { if(q_min[head_min]<q_max[head_max]) left1=q_min[head_min++]; else left2=q_max[head_max++]; } if(a[q_min[head_min]]-a[q_max[head_max]]>=m) maxx=max(maxx,i-max(left1,left2)); } printf("%d\n",maxx); } return 0; } /* 5 2 3 1 -1 2 -6 5 5 1 3 1 2 3 4 5 6 0 0 -1 0 2 1 125 -5 */
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; int a[maxn], q1[maxn], q2[maxn]; int main() { int n, m, k; while(cin>>n>>m>>k) { for(int i = 0; i<n; i++) { scanf("%d", &a[i]); } int st1 = 0, st2 = 0, ed1 = 0, ed2 = 0, ans = 0, now = 0; for(int i = 0; i<n; i++) { while(st1<ed1&&a[q1[ed1-1]]<a[i]) //q1维护一个单调递减的数列,这样队头元素是最大值, 第二个是第二大的值 ed1--; while(st2<ed2&&a[q2[ed2-1]]>a[i]) //q2维护一个单调递增的数列, 队头是最小值。 ed2--; q1[ed1++] = q2[ed2++] = i; while(st1<ed1&&st2<ed2&&a[q1[st1]]-a[q2[st2]]>k) { //如果最大值-最小值大于k if(q1[st1]<q2[st2]) { now = q1[st1++]+1; //如果最大值在序列中的位置小于最小值 } else { now = q2[st2++]+1; } } if(st1<ed1&&st2<ed2&&a[q1[st1]]-a[q2[st2]]>=m) { ans = max(ans, i-now+1); //只有最大值-最小值大于等于m的时候才更新ans } } cout<<ans<<endl; } }