单调队列总结

Posted zhgyki

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列总结相关的知识,希望对你有一定的参考价值。

单调队列

就是保持队列中的元素始终保持单调性,这个数据结构就是单调队列

它的作用就是维护最值、求第一个比i小(大)的数的下标等等

还有个单调栈来着,不过我们可以用一个双端队列就足够了

如果要维护最大值,就用单调递减队列,反之,用递增队列

1、hdu3530 Subsequence 单调队列入门题

这题求的是最大值减去最小值不小于m不大于k的最长长度

这题用单调队列维护最大值和最小值即可

技术分享图片
#include<iostream>
using namespace std;
#define MAX 1000005
int a[MAX],deq1[MAX],deq2[MAX];
int Min[MAX],Max[MAX];
int n,m,k;
int main()
{
    while(cin>>n>>m>>k){
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int head1=0,tail1=0;
    int head2=0,tail2=0;
    int ans=0;
    int now=1;
    for(int i=1;i<=n;i++)
    {
        while(head1<tail1&&a[deq1[tail1-1]]<a[i]) tail1--;
        while(head2<tail2&&a[deq2[tail2-1]]>a[i]) tail2--;
        deq1[tail1++]=i;
        deq2[tail2++]=i;
        //cout<<head1<<head2<<endl;
           while(head1<tail1&&head2<tail2&&a[deq1[head1]]-a[deq2[head2]]>k)
            {
                if(deq1[head1]<deq2[head2])now=deq1[head1++]+1;
                else now=deq2[head2++]+1;
            }
            if(head1<tail1&&head2<tail2&&a[deq1[head1]]-a[deq2[head2]]>=m)
            {
                if(ans<i-now+1)ans=i-now+1;
            }
    }
    cout<<ans<<endl;
    }
}
hdu3530

2、poj2559 Largest Rectangle in a Histogram

求包含的最大面积,维护两个单调队列,队列求第一个比i大(小)的数

技术分享图片
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define MAX 1000005
int deq[MAX];
long long L[MAX],R[MAX];
long long h[MAX];
int n;
int main()
{
    while(~scanf("%d",&n)){
        if(n==0) break;
    memset(h,-1,sizeof(h));
    for(int i=1;i<=n;i++)
        scanf("%lld",&h[i]);
    memset(deq,0,sizeof(deq));
    int head=0,tail=0;
    deq[tail++]=0;
    for(int i=1;i<=n;i++)
    {
        while(head<tail&&h[deq[tail-1]]>=h[i])tail--;
         L[i]=deq[tail-1]+1;
        deq[tail++]=i;
    }
    memset(deq,0,sizeof(deq));
    deq[tail++]=n+1;
    for(int i=n;i>0;i--)
    {
        while(head<tail&&h[deq[tail-1]]>=h[i])tail--;
        R[i]=deq[tail-1]-1;
        deq[tail++]=i;
    }
    long long res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,h[i]*(R[i]-L[i]+1));
    }
    printf("%lld
",res);
    }
}
poj2559

3、poj2823 Sliding Window

维护两个单调队列求最大和最小值即可

技术分享图片
#include<iostream>
#include<stdio.h>
using namespace std;
#define MAX 1000000
int n,k;
int deq1[MAX],deq2[MAX];
int Max[MAX],Min[MAX];
int a[MAX];
int main()
{
    while(~scanf("%d %d",&n,&k))
    {
        int head1=0,tail1=0;
        int head2=0,tail2=0;
        for(int i=1;i<=n;i++)
         {
                scanf("%d",&a[i]);
                while(head1<tail1&&a[deq1[tail1-1]]<a[i]) tail1--;
                while(head2<tail2&&a[deq2[tail2-1]]>a[i]) tail2--;
                deq1[tail1++]=i;
                deq2[tail2++]=i;
                while(head1<tail1&&i-deq1[head1]>=k) head1++;
                while(head2<tail2&&i-deq2[head2]>=k) head2++;
                Max[i]=a[deq1[head1]];
                Min[i]=a[deq2[head2]];
         }
         for(int i=k;i<=n;i++){
             printf("%d ",Min[i]);
         }
         putchar(
);
         for(int i=k;i<=n;i++){
            printf("%d ",Max[i]);
         }
         putchar(
);
    }
}
poj2559

4、poj3017 Cut the Sequence

题意是求把数列分成几块后每块的最大值的最小值,注意每块的和不超过M

题解:dp[i]表示分块后的最小值

则dp[i]=min{dp[i],dp[j]+max(a{j+1,i} } 

这个dp可以用单调队列优化,维护一个单调递减队列,然后遍历队列里的值

技术分享图片
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
#define MAX 100005
int n;
ll m;
ll a[MAX];
ll dp[MAX];
struct node
{
    int index;
    ll val;
}deq[MAX];
int main()
{
    while(~scanf("%d %lld",&n,&m)){
    bool flag=false;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        if(a[i]>m)
          flag=true;
    }
    if(flag)
    {
        printf("-1
");
       continue;
    }
    else
    {
        int head=0,tail=0;
        int pos=1;
        ll sum=a[1];
        deq[tail].val=dp[1]=a[1];
        deq[tail++].index=1;
        for(int i=2;i<=n;i++)
        {
            sum+=a[i];
            while(sum>m&&pos<i)
                sum-=a[pos],pos++;
            while(head<tail&&deq[tail-1].val<=a[i]) tail--;
            deq[tail].val=a[i];deq[tail++].index=i;
            while(head<tail&&deq[head].index<pos)
                head++;
            dp[i]=dp[pos-1]+deq[head].val;
            for(int j=head;j<tail-1;j++)
                dp[i]=min(dp[i],dp[deq[j].index]+deq[j+1].val);
        }
        printf("%lld
",dp[n]);
    }
}
}
poj3017

 

以上是关于单调队列总结的主要内容,如果未能解决你的问题,请参考以下文章

总结与心得(持续更新)

心得单调队列

刷题总结——生日礼物(bzoj1293单调队列)

dp 单调性优化总结

单调队列优化DP

单调队列