zoukankan      html  css  js  c++  java
  • 单调队列总结

    单调队列

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

    它的作用就是维护最值、求第一个比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
  • 相关阅读:
    HDU 1828 Picture (线段树:扫描线周长)
    [USACO18OPEN] Multiplayer Moo (并查集+维护并查集技巧)
    NOIP2016 天天爱跑步 (树上差分+dfs)
    NOIP2013 华容道 (棋盘建图+spfa最短路)
    NOIP2015 运输计划 (树上差分+二分答案)
    NOIP2018 前流水账
    luogu P2331 [SCOI2005]最大子矩阵
    luogu P2627 修剪草坪
    CF101D Castle
    luogu P2473 [SCOI2008]奖励关
  • 原文地址:https://www.cnblogs.com/zhgyki/p/9563338.html
Copyright © 2011-2022 走看看