单调队列deque

这个deque,caiji整整看了俩小时,,,正所谓代码不长,句句皆精华,,

deque


双向队列,支持双向进入

典型例题


滑块问题

题目传送门

一个中心:
  • 维护一个队列,这个队列是单调的。
两个基本点:
  • 在一开始的时候,要判断长度与给定滑块长度的关系,如果超过了长度,则使队头出队
  • 满足第一点后,与队尾进行比较,看看是不是满足单调。不满足则弹出队尾,然后再判断,使队中元素满足单调。

然后在插入该元素就行

//
// Created by Arc on 2021/1/28.
//
#include <iostream>
#include <queue>
using namespace std;

deque<int> q;
int a[10000];
int main()
{
   int m,n;
   cin>>n>>m;
    for (int i = 0; i < n; ++i) {
        cin>>a[i];
        while(!q.empty()&&q.front()<i-m){//如果数量超标,则弹出对头
            q.pop_front();
        }
        while(!q.empty()&&a[q.back()]>=a[i]){
            /*如果要进入的数比队尾还小,队尾出列
             * 一直比较到这个数可以满足单调
            */
            q.pop_back();
        }
        q.push_back(a[i]);
        cout<<q.front()<<" ";
    }

}

最大子序列

题意

给你n个数,求出最大连续子段和,并且该子段长度不超过m,且不能为空子段。

思路

求完前缀和后,跟上面基本是一样的

#include <iostream>
using namespace std;
typedef long long ll;
int n,m,ans;
const int INF=0x3f3f3f3f;
const int maxn=300000+10;
int a[maxn],s[maxn];
deque<int> Q;
int main()
{
    cin>>n>>m;
    ans=-INF, s[0]=0;
    Q.push_back(0);
    for(int i=1;i<=n;i++)
    {
        cin>>a[i], s[i]=s[i-1]+a[i];
        while(!Q.empty() && Q.front()<i-m)
            Q.pop_front();
        ans=max(ans,s[i]-s[Q.front()]);
        while(!Q.empty() && s[Q.back()]>=s[i])
            Q.pop_back();
        Q.push_back(i);
    }
    cout<<ans<<endl;
}

小结

单调队列是一个思想,可以通过维护队列的单调性,来取某一段的maxmin,复杂度的话,每个数进出一次,为o(n)
参考博客:https://www.cnblogs.com/I-Love-You-520/p/13454305.html

为了自己,和那些爱你的人
原文地址:https://www.cnblogs.com/zhmlzhml/p/14340569.html