2021-7-8 单调队列及其应用

Posted KaaaterinaX

tags:

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

不是优先队列!不是优先队列!

我是fw呜呜呜!看了好久了!

单调队列是既是单调,同时也符合队列先进先出的特点。(入队顺序在前的元素不能排到入队顺序在后的元素后面,而且队内元素有单调性)

假设要求队列都必须是单调递增的数字,而且入队顺序是固定的:
入队顺序:
1 3 2 4 5

队列:
1
1 3
1 2(重点在这步,当要入队的数字不符合递增的条件,那么就让它持续向前走,并删除其后面的元素。)
1 2 4
1 2 4 5

最基础的例题:
求m区间内的最小值

const int maxn=2e6+7;

int a[maxn];
int dl[maxn];
int idx[maxn];
int le=1,ri=0;

int main()
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    
    for(int i=1;i<=n;i++)
        cout<<dl[le]<<endl;//队首维护的是合法区间内最小值
        while(le<=ri&&a[i]<dl[ri])
            //删除不应该出现在队列中的元素(不可能成为答案的元素)
            ri--;
        
        dl[++ri]=a[i];//新元素入队
        idx[ri]=i;
        if(i-idx[le]>=m) le++;//如果区间的左边界不在符合条件,则令队头出队
    

多重背包的单调队列优化:

//单调队列优化多重背包

const int maxn=2e4+7;
ll last[maxn];
ll now[maxn];

//单调队列
ll q[maxn];


int main()
    int N,V;
    cin>>N>>V;
    for(int i=1;i<=N;i++)
        ll v,w,s;
        cin>>v>>w>>s;
        memcpy(last,now,sizeof last);
        for(int j=0;j<v;j++)
            int h=1,t=0;//单调队列头与尾
            for(int k=j;k<=V;k+=v)
                //不能用的队头出队列
                if(h<=t&&q[h]<k-s*v)
                    h++;
                
                //运用队头更新now
                if(h<=t)
                    now[k]=max(last[k],last[q[h]]+((k-q[h])/v)*w);
                
                //不符合就往前移
                while(h<=t&&last[q[t]]+(k-q[t])/v*w<=last[k])
                    t--;
                
                //下标入队列
                q[++t]=k;
            
        
    
    ll ans=0;
    for(int i=0;i<=V;i++)
        ans=max(ans,now[i]);
    
    cout<<ans<<endl;


以上是关于2021-7-8 单调队列及其应用的主要内容,如果未能解决你的问题,请参考以下文章

单调队列与应用

单调队列(双端队列) poj2823 hdoj3415 hdoj3530

单调栈以及单调队列

单调队列怎么用java实现

模板 - 数据结构 - 单调队列/单调栈

滑动窗口