单调队列

单调队列

Sliding Window

题意:

Window positionMinimum valueMaximum value
[1  3  -1] -3  5  3  6  7 -13
 1 [3  -1  -3] 5  3  6  7 -33
 1  3 [-1  -3  5] 3  6  7 -35
 1  3  -1 [-3  5  3] 6  7 -35
 1  3  -1  -3 [5  3  6] 7 36
 1  3  -1  -3  5 [3  6  7]37

解析:

最大值队列,单调递减
最小值队列,单调递增

模拟算法步骤

首先k==3,取max:

1.(1,1)预入队,max=1,队空直接入队              left=1,rigjt=1

2.(3,2)预入队,max=3,去掉比3小的元素,(1,1)出队,出队结束,(3,2)入队                                                             

3.(-1,3)预入度,max=3,出队结束,(-1,3)入队                                                                                                   

4.(-3,5)预入队,max=3,出队结束,(-3,4)入队                                                      

5.(5,5)预入队,max=5,(3,2),(-1,3),(-3,5)出队,出队结束,(5,5)入队,                         

6.(3,3)预入队,max=5,出队结束,

7.(6,6)预入队,max=6,(5,5),(3,3)出队,出队结束

8.(7,7)预入队,max=7,(6,6)出队,出队结束

输出答案的时候要判断队列首是否大于i-m+1

这里用数组实现,que保存单调队列的坐标

移窗问题:

每次移动一个距离,求k范围内的最大值和最小值

可以用单调队列或者优先队列解决

单调队列写法:

ac:

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define MAXN 1000005
using namespace std;

int a[MAXN];
int queA[MAXN],queB[MAXN];//记录坐标
int ansA[MAXN],ansB[MAXN];

/*
最大值队列,单调递减
最小值队列,单调递增
*/


void quemax(int st,int ed,int m)
{
    int left=1,right=0;
    for(int i=st;i<=ed;i++)
    {
        while(right>=left&&a[queA[right]]<=a[i])right--;//删掉比a[i]小的
        queA[++right]=i;//压入队列
        if(i-m+1>=1)//防止越界
        {
            while(queA[left]<i-m+1)left++;//去掉队列中i已经小于i-m+1的元素
            ansA[i]=a[queA[left]];
        }
    }
}

void quemin(int st,int ed,int m)
{
    int left=1,right=0;
    for(int i=st;i<=ed;i++)
    {
        while(right>=left&&a[queB[right]]>=a[i])right--;//删掉比a[i]大的
        queB[++right]=i;
        if(i-m+1>=1)
        {
            while(queB[left]<i-m+1)left++;//去掉队列中i已经小于i-m+1的元素
            ansB[i]=a[queB[left]];
        }
    }
}

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        quemin(1,n,m);
        quemax(1,n,m);
        for(int i=m;i<n;i++)
            printf("%d ",ansB[i]);
        printf("%d\n",ansB[n]);
        for(int i=m;i<n;i++)
            printf("%d ",ansA[i]);
        printf("%d\n",ansA[n]);
    }
    return 0;
}

优先队列写法:

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#define MAXN 1000005
using namespace std;
struct node
{
    int x,j;
    friend bool operator <(node a,node b)
    {
        return a.x>b.x;
    }
}ee[MAXN];
 
struct node2
{
    int x,j;
    friend bool operator <(node2 a,node2 b)
    {
        return a.x<b.x;
    }
}dd[MAXN];
 
priority_queue<node> quex;
priority_queue<node2> quen;
int aa[MAXN],bb[MAXN];
int ac=0,bc=0;
 
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&ee[i].x),ee[i].j=i;
        dd[i].x=ee[i].x;
        dd[i].j=i;
    }
    for(int i=1;i<k;i++)
    {
        quex.push(ee[i]);
        quen.push(dd[i]);
    }
    for(int i=k;i<=n;i++)
    {
        quex.push(ee[i]);
        quen.push(dd[i]);
        while(quex.top().j+k<=i)
        {
            quex.pop();
            if(quex.empty())
                break;
        }
        while(quen.top().j+k<=i)
        {
            quen.pop();
            if(quen.empty())
                break;
        }
        aa[ac++]=quex.top().x;
        bb[bc++]=quen.top().x;
    }
    for(int i=0;i<=n-k;i++)
    {
        printf("%d",aa[i]);
        if(i!=n-k)
            printf(" ");
        else
            printf("\n");
    }
    for(int i=0;i<=n-k;i++)
    {
        printf("%d",bb[i]);
        if(i!=n-k)
            printf(" ");
        else
            printf("\n");
    }
    return 0;
}

志愿者选拔

数据较大建议使用scanf,printf 不推荐使用STL

解析:

单调队列

ac:

#include<stdio.h>
#include<string.h>
#define maxn 1000005
using namespace std;
 
struct node
{
    int x,val;
}que[maxn];
 
char name[6],na[10],start[12];
int rp;
int i,j,k,head=0,tail=-1,last=0,K=1;
 
void push(int rp)
{
    while(tail>=head&&que[tail].val<=rp)
        tail--;
    que[++tail]={K++,rp};
}
 
void query()
{
    while(tail>=head&&que[head].x<=last) head++;
    if(tail>=head)
        printf("%d\n",que[head].val);
    else
        printf("-1\n");
}
 
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        i,j,k,head=0,tail=-1,last=0,K=1;
        scanf("%s",start);
        while(scanf("%s",name)!=EOF)
        {
            if(name[0]=='E')
                break;
            if(name[0]=='C')
            {
                scanf("%s%d",na,&rp);
                push(rp);
            }
            else if(name[0]=='Q')
            {
                query();
            }
            else
                last++;//右移
        }
    }
    return 0;
}

题目:F Planting Trees(单调队列,尺取)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值