单调队列经典题目 FOJ 1894

 Problem 1894 志愿者选拔

Accept: 1291    Submit: 4070
Time Limit: 1500 mSec    Memory Limit : 32768 KB

 Problem Description

世博会马上就要开幕了,福州大学组织了一次志愿者选拔活动。
参加志愿者选拔的同学们排队接受面试官们的面试。参加面试的同学们按照先来先面试并且先结束的原则接受面试官们的考查。
面试中每个人的人品是主要考查对象之一。(提高人品的方法有扶老奶奶过街,不闯红灯等)
作为主面试官的John想知道当前正在接受面试的同学队伍中人品值最高的是多少。于是他请你帮忙编写一个程序来计算。

 Input

输入数据第一行为一整数T,表示有T组输入数据。
每组数据第一行为”START”,表示面试开始
接下来的数据中有三种情况:
 输入含义
1C NAME RP_VALUE名字为NAME的人品值为RP_VALUE的同学加入面试队伍。(名字长度不大于5,0 <= RP_VALUE <= 1,000,000,000)
2G排在面试队伍最前面的同学面试结束离开考场。
3Q主面试官John想知道当前正在接受面试的队伍中人品最高的值是多少。
最后一行为”END”,表示所有的面试结束,面试的同学们可以依次离开了。
所有参加面试的同学总人数不超过1,000,000

 Output

对于每个询问Q,输出当前正在接受面试的队伍中人品最高的值,如果当前没有人正在接受面试则输出-1。

 Sample Input

2STARTC Tiny 1000000000C Lina 0QGQENDSTARTQC ccQ 200C cxw 100QGQC wzc 500QEND

 Sample Output

10000000000-1200100500


这里模仿了别人两种写法
第一种比较好理解




可以用一个双端队列q来维护这个最值,q里面只保存可能是最值的元素(位置,值)。
对于一个进队操作,我们将它从队尾开始插入,比较队尾元素和当前插入元素,
如果当前元素的值优于队尾元素,显然队尾元素在任何时刻都不可能是最值元素,
我们可以将它删除。重复这个过程直至队尾元素优于当前元素或队列为空。
对于出队操作,我们只需要从队首元素开始枚举,如果队首元素的位置已经出队,
则将其删除,依次处理,这样我们双端队列里面的元素E(place,value)


#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 1000001
struct node
{
    int rp;
    int n;
}q[maxn];

int main()
{
    int t;
    char str[10];
    int i,j;
    cin>>t;
    while(t-- && scanf("%s",str))
    {
        for(i=0;i<maxn;i++)
            q[i].rp=-1;
        int a=-1,i=0,now=0,top=0;
        while(scanf("%s",str))
        {
            if(str[0]=='E')
                break;
            if(str[0]=='C')
            {
                int temp;
                scanf("%s %d",str,&temp);
                while(a>=top && q[a].rp<temp)
                    a--;
                q[a+1].rp=temp;
                q[a+1].n=i;
                a++;
                i++;
            }
            else if(str[0]=='G')
            {
                if(now<=i)
                {
                    if(q[top].n==now)
                        top++;
                        now++;
                }
            }
            else
            {
                if(top<=a)
                    printf("%d\n",q[top].rp);
                else
                    puts("-1");
            }
        }
    }
    return 0;
}


另外一种就是模板式的单调队列
#include<stdio.h>
#include<string.h>
#define maxn 1000000
struct que{
    int x,val;
    que(int xx,int yy):x(xx),val(yy){}
    que(){};
}q[maxn];
int main()
{
    int t;
    char name[6],na[10];
    int rp;
    scanf("%d",&t);
    while(t--)
    {
        int i,j,k,head=0,tail=-1,leave=0,K=1;
        scanf("%*s");
        while(scanf("%s",name)!=EOF)
        {
            if(strcmp(name,"END")==0) break;
            if(name[0]=='C')
            {
                scanf("%s%d",na,&rp);
                while(tail>=head&&q[tail].val<=rp) tail--;
                que now(K++,rp);
                q[++tail]=now;
            }
            else if(name[0]=='Q')
            {
                while(tail>=head&&q[head].x<=leave) head++;
                if(tail>=head) printf("%d\n",q[head].val);
                else printf("-1\n");
            }
            else leave++;
        }
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值