HDU3530(单调队列)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3530

题意

  给出一个数列 ai ,及一个范围 [m,k] ,求这个数列中所有连续的区间的最大值与最小值之差在[m,k]中,的区间长度最大是多少。

思路(单调队列+尺取法)

  满足某一要求,求最大或最小区间长度很容易想到尺取法,而怎么快速求某一区间的最大最小值,很容易想到RMQ之类的算法,比如线段树、ST表、树状数组等,但是尺取法本身就是区间滑动的过程,所以也可以通过单调队列顺便求出区间的最大值和最小值,总体思路没什么问题,需要注意一个问题:左右端点如何滑动。
  设左右端点为L,R,如果当前区间满足条件,那么应该尽可能的扩大区间,直到不能扩大为止,这个之后缩小左端点,L++直到满足条件,对每一次满足条件后的区间长度求一次max。最大值和最小值分别用两个单调队列记录。

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000009
#define ll long long
#define inf 1000000009000000000
#define IOS ios::sync_with_stdio(false)

int ff[maxn];
pair<int,int> dq1[maxn],dq2[maxn];

int main()
{
    IOS;
    int n,m,k;
    while(cin>>n>>m>>k)
    {
        for(int i=1; i<=n; i++)
            cin>>ff[i];

        int L=1,ans=0;
        int le1=1,ri1=1;
        int le2=1,ri2=1;
        for(int i=1; i<=n; i++)
        {
            if(le1==ri1)
                dq1[ri1++]=make_pair(i,ff[i]);
            else
            {
                while(le1!=ri1&&dq1[ri1-1].second>ff[i])
                    ri1--;
                dq1[ri1++]=make_pair(i,ff[i]);
            }

            if(le2==ri2)
                dq2[ri2++]=make_pair(i,ff[i]);
            else
            {
                while(le2!=ri2&&dq2[ri2-1].second<ff[i])
                    ri2--;
                dq2[ri2++]=make_pair(i,ff[i]);
            }

            //cout<<dq1[le1].second<<" w "<<dq2[le2].second<<" l r "<<le2<<" "<<ri2<<endl;
            while(le1!=ri1&&le2!=ri2&&abs(dq1[le1].second-dq2[le2].second)>k)
            {
                L++;
                if(le1!=ri1&&dq1[le1].first<L)
                    le1++;
                if(le2!=ri2&&dq2[le2].first<L)
                    le2++;
            }

            if(le1!=ri1&&le2!=ri2&&abs(dq1[le1].second-dq2[le2].second)>=m)
            {
                ans=max(ans,i-L+1);
                //cout<<"asn="<<ans<<endl;
            }
            //cout<<L<<" "<<i<<endl;
        }
        cout<<ans<<"\n";
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值