单调队列

单调队列

今天问了长者有关单调队列的知识,单调队列这种东西其实用途并不是特别的广泛,只是在处理区间上询问的时候比较管用,而且这种询问有限制,比如:
一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。
这种类似的题目,每次询问前m个数中最小的,显然暴力的话是O(n * m)的每个点枚举一遍m,就是这样,但是暴力显然会TLE,那有什么办法呢?
RMQ是可以的,但是有一个问题,就是MLE,2000000 * 20,会炸空间,线段树显然是可以的,但是还不是最优的。所以我们引出单调队列这种东西,解决序列上滑块的问题(m这个区间在序列上动来动去,就像是个滑块^_^).

单调队列?

我们制作一个严格上升或下降的队列,它的队首是你处理当前区间的最大(最小)值,然后进行删除和加入的操作。
加入: 我们假设有8,1,2,3,7,9,6.这样的一个序列,我们想要一个单调上升的序列,这样就可以保证队首是最小的。我们加入元素的时候我们要存下每个值在原序列中的下标,因为,我们只有处理[i-m,i]这样的一个区间,如果队首元素的下标不在这个区间,显然就毫无意义了不。好,我们开始加入元素,我们每次添加元素,从队尾开始比较,直到找到比它小的数替换掉。
假设没有删除操作
第一次 :8
第二次:1(1 < 8 所以 我们替换掉8)
第三次:1,2.
第四次:1,2,3.
第五次:1,2,3,7.
第六次:1,2,3,7,9.
第七次:1,2,3,6.(跟7,9,比较都小,所以替换,尾指针直到6的位置)。

删除
删除其实很简单,我们比较队首的下标如果不在范围内直接删掉。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;

#define REP(i,a,b) for(register int i = (a), i##_end_ = (b); i <= i##_end_ ; ++i)

inline int read()
{
    char c = getchar();register int fg = 1,sum = 0;
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c  >= '0' && c <= '9')
    {
        sum =sum * 10 + c - '0';
        c = getchar();
    }
    return fg * sum;
}

const int maxn = 2000000+10;

struct T
{
    int val,pos;
};

struct que
{
    int l,r;
    T a[maxn];
    que(){l = 1, r = 0;}
    inline void putin(T x)//加入
    {
        while(r >= l && a[r].val > x.val)r--;
        a[++r] = x;
    }

    inline void pop(int pos)//删除
    {
        while(r >= l && a[l].pos < pos)l++;
    }
    void print()
    {
        for(int i=l;i<=r;i++)
            printf("%d ",a[i].val);
        printf("\n");
    }
    inline int top()
        {return a[l].val;}
}q;

int n,m,f[maxn];

int main()
{
    n = read(),m = read();
    REP(i,1,n)f[i] = read();
    puts("0");
    q.putin((T){f[1],1});
    REP(i,2,n)
    {   q.print();
        if(i-m>=0)q.pop(i-m);

        printf("%d\n",q.top());
        q.putin((T){f[i],i});
    }
    return 0;
}
Python的单调队列是一种用于解决某些特定问题的数据结构。它是队列的一种变体,可以快速查询当前队列中的最大或最小元素。 单调队列通常用于需要维护当前滑动窗口中的最大或最小值的情况。例如,假设我们有一个长度为n的数组arr和一个窗口大小为k的滑动窗口。我们想要找到每个窗口中的最大值。单调队列就可以帮助我们在O(n)的时间复杂度内实现。 实现单调队列需要两个操作:push(x)和pop()。push(x)用于向队列的尾部添加元素x,而pop()用于从队列的头部删除元素。这两个操作具有O(1)的时间复杂度。 当我们向队列中添加一个新元素时,为了维护队列的单调性,我们需要从队列的尾部删除一些元素。具体来说,我们从队列的尾部开始,不断地删除比新元素小的元素,直到队列为空或者新元素大于等于队列尾部元素为止。这样,我们就可以保证队列中的元素是以递减顺序排列的。 当我们需要查询当前队列中的最大或最小值时,只需访问队列头部的元素即可。由于队列中的元素是以递减的顺序排列的,所以头部元素就是最大值(或最小值)。 总的来说,Python的单调队列是一种高效的数据结构,可以用于解决一些特定问题,如滑动窗口中的最大(或最小)值。它具有O(n)的时间复杂度,并且可以通过push(x)和pop()操作来维护队列的单调性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值