把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

单调队列

单调队列

顾名思义,单调队列就是具有单调性的队列,我们需要用双端队列来实现。
双端队列与普通队列的唯一区别就是它可以从两边弹出。
打个形象一点儿的比方

一群人在食堂排队打饭

这个时候来了一个新的小伙伴

这个小伙伴很霸道地想要去插队,其他小伙伴们肯定不会同意,但是打不过这个新伙伴,于是就被赶走了。

但是呢,它又打不过最前面的那个6,于是就只有乖乖地站在它后面

过了一会儿,6打完了饭离开了队列,而5还在队列中继续打饭

以上大概就是单调队列的操作规则

单调队列的应用

百度上对单调队列的解释是:
不断地向缓存数组里读入元素,也不时地去掉最老的元素,不定期的询问当前缓存数组里的最小的元素。

由于单调队列具有单调性,而且有淘汰旧元素的规则,我们通常用它来维护某个特定范围内的最值。

举几个经典的例子:

滑动窗口

luogu P1886
非常明显的满足单调队列的性质
用两个单调队列分别维护最大值和最小值。
每滑动一次就要考虑两件事情

  1. 淘汰掉虽然很优秀(很大or小)但是已经不在范围内的元素 (从队头)
  2. 淘汰掉不够优秀的元素(即队列中比当前元素更(小or大)的元素,由于它们出现在当前元素之前,又没有当前元素优秀,所以当窗口继续滑动时,它们有生之年都不可能成为最值了,只能成为时代的眼泪)
    (从队尾)
#include<cstdio>
#include<deque>
using namespace std;
#define MAXN 1000005
int n,k;
int a[MAXN],ans[MAXN];
deque<int>Q;//维护在原数组中的编号 
void Min()
{
    int j;
    for(int i=1;i<=n;i++)
    {
        while(!Q.empty())//维护队尾最小值
        {
            j=Q.back();
            if(a[j]>=a[i])
                Q.pop_back();
            else break; 
        }
        Q.push_back(i);
        while(!Q.empty())
        {
            j=Q.front();
            if(i-j>=k)
                Q.pop_front();
            else break;
        }
        ans[i]=a[Q.front()];
    }
    for(int i=k;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
}
void Max()
{
    Q.clear();//注意清零 
    int j;
    for(int i=1;i<=n;i++)
    {
        while(!Q.empty())
        {
            j=Q.back();
            if(a[j]<=a[i])
                Q.pop_back();
            else break;
        }
        Q.push_back(i);
        while(!Q.empty())
        {
            j=Q.front();
            if(i-j>=k)
                Q.pop_front();
            else break;
        }
        ans[i]=a[Q.front()];
    }
    for(int i=k;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
}
int main()
{
    scanf("%d %d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    Min();
    Max();
    return 0;
}

单调队列与优先队列

网上看到的,比较有道理:
单调队列与优先队列的区别:单调队列的长度取决于输入数据的合法性,而优先队列的长度始终与输入数据的数量等同。而他们的单调性都是单调递减或单调递增。

而我自己的理解,就是:
他们同样都维护了一个单调性
但是优先队列对数据照盘全收,而单调队列有淘汰旧元素的过程。所以你不好好努力,不够优秀的话,是没有办法在单调队列里活下来的

posted @ 2023-03-19 23:16  Starlight_Glimmer  阅读(13)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end