单调队列

关闭

单调队列

1435人阅读 评论(0) 收藏 举报
分类:

单调队列是这样一个队列,队列中的所有元素是单调递增或者单调递减。它可以在队首或队尾删除元素,但是只能在队尾插入元素。由于每个元素入队和出队一次,所以维护队列的均摊时间复杂度为O(1)。


题目:http://poj.org/problem?id=2823


题意:给一个数组a[],求它连续m个元素中的最小值和最大值。比如输入:


8 3
1 3 -1 -3 5 3 6 7


那么输出:


-1 -3 -3 -3 3 3
3 3 5 5 6 7


分析:我们用一个数组q[]来记录这个单调队列所有元素的下标,h为队首,t为队尾。那么现在就来模拟样例:


首先h初始化为1,t初始化为0。


(1)插入第一个元素       q[] = {1},h = 1,t = 1    队列中的元素个数小于3,不输出。

(2)插入第二个元素       q[] = {1,2},h = 1,t = 2  队列中的元素个数小于3,不输出。

(3)插入第三个元素       q[] = {3},h = 1,t = 1    因为3号元素比1和2号元素都小,所以一直挤到最

                       前面,1号和2号元素出队,此时队列中的元素个数等于3,输出队首元素值。

(4)插入第四个元素       q[] = {4},h = 1,t = 1    同样的道理,3号元素出队,输出队首元素值。

(5)插入第五个元素       q[] = {4,5},h = 1,t = 2  输出队首元素。

(6)插入第六个元素       q[] = {4,6},h = 1,t = 2  输出队首元素。

(7)插入第七个元素       q[] = {6,7},h = 2,t = 3  输出队首元素。

(8)插入第八个元素       q[] = {6,7,8},h = 2,t = 4 输出队首元素。


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 1000005;

int n,m;
int a[N],q[N];

void MinQ()
{
    int t = 0 ,h = 1;
    q[1] = 1;
    for(int i=1; i<=n; i++)
    {
        if(i - q[h] == m) h++;
        if(t == h-1 || a[i] > a[q[t]])
        {
            t++;
            q[t] = i;
        }
        else
        {
            while(t >= h && a[i] <= a[q[t]])
            {
                q[t] = i;
                t--;
            }
            t++;
        }
        if(i >= m) printf("%d ",a[q[h]]);
    }
    puts("");
}

void MaxQ()
{
    int t = 0 ,h = 1;
    q[1] = 1;
    for(int i=1; i<=n; i++)
    {
        if(i - q[h] == m) h++;
        if(t == h-1 || a[i] < a[q[t]])
        {
            t++;
            q[t] = i;
        }
        else
        {
            while(t >= h && a[i] >= a[q[t]])
            {
                q[t] = i;
                t--;
            }
            t++;
        }
        if(i >= m) printf("%d ",a[q[h]]);
    }
    puts("");
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        scanf("%d",&a[i]);
    MinQ();
    MaxQ();
    return 0;
}

 


题目:http://acm.fzu.edu.cn/problem.php?pid=1894

 

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 1000005;

struct Node
{
    int id;
    int val;
    Node(int id = 0,int val = 0)
    {
        this->id = id;
        this->val = val;
    }
};

Node q[N];
char str[105];

int main()
{
    int T;
    scanf("%d",&T);
    q[0] = -1;
    while(T--)
    {
        scanf("%s",str);
        int i = 0,j = 1;
        int head = 1,tail = 0;
        while(scanf("%s",str))
        {
            if(!strcmp(str,"END")) break;
            if(str[0] == 'C')
            {
                int val;
                scanf("%s %d",str,&val);
                while(head <= tail && q[tail].val <= val) tail--;
                q[++tail] = Node(++i,val);
            }
            else if(str[0] == 'G')
            {
                while(head <= tail && q[head].id <= j) head++;
                j++;
            }
            else
                printf("%d\n",head > tail ? -1:q[head].val);
        }
    }
    return 0;
}


2
1
 
 
查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
  • 个人资料
    • 访问:2193004次
    • 积分:23590
    • 等级:
      积分:23590
    • 排名:第299名
    • 原创:478篇
    • 转载:42篇
    • 译文:0篇
    • 评论:488条
  • 最新评论
收藏助手
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值