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

 

posted @ 2017-10-10 18:15  Aragaki  阅读(217)  评论(0编辑  收藏  举报