POJ-3481 Double Queue

本文介绍了一种银行系统的客户调度算法,通过使用双队列(一个基于优先级高低,另一个基于优先级逆序)来处理客户的请求。该算法支持四种操作:停止服务、添加客户至等待队列、服务优先级最高的客户以及服务优先级最低的客户。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Double Queue
题目链接
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 18268 Accepted: 7859
Description

The new founded Balkan Investment Group Bank (BIG-Bank) opened a new office in Bucharest, equipped with a modern computing environment provided by IBM Romania, and using modern information technologies. As usual, each client of the bank is identified by a positive integer K and, upon arriving to the bank for some services, he or she receives a positive integer priority P. One of the inventions of the young managers of the bank shocked the software engineer of the serving system. They proposed to break the tradition by sometimes calling the serving desk with the lowest priority instead of that with the highest priority. Thus, the system will receive the following types of request:

0 The system needs to stop serving
1 K P Add client K to the waiting list with priority P
2 Serve the client with the highest priority and drop him or her from the waiting list
3 Serve the client with the lowest priority and drop him or her from the waiting list
Your task is to help the software engineer of the bank by writing a program to implement the requested serving policy.

Input

Each line of the input contains one of the possible requests; only the last line contains the stop-request (code 0). You may assume that when there is a request to include a new client in the list (code 1), there is no other request in the list of the same client or with the same priority. An identifier K is always less than 106, and a priority P is less than 107. The client may arrive for being served multiple times, and each time may obtain a different priority.

Output

For each request with code 2 or 3, the program has to print, in a separate line of the standard output, the identifier of the served client. If the request arrives when the waiting list is empty, then the program prints zero (0) to the output.

Sample Input

2
1 20 14
1 30 3
2
1 10 99
3
2
2
0
Sample Output

0
20
30
10
0
Source

题目大意
有 4 种:
0 停止操作
1 加入一个编号为k,优先级为p的人
2 输出当期优先级最高的人的编号并删除这个人
3 输出当期优先级最低的人的编号并删除这个人
时间:1s
空间:64MB

题解
很明显可以用平衡树来维护。(我写了Treap)

也可以用两个堆(一个大根一个小根)来维护,vis数组表示编号为k的人是否在队列里。
1 操作相当于修正vis,再往两个堆里都推入这个元素。
2 操作删除第一个满足在队列里的堆顶(不在就删掉)
3 操作同理。
由于没有明确操作次数,如果只有 0、1 和 2 操作,那么很可能小根堆会炸掉。
不过也不用太担心,因为时限是 1 秒,我们开到 10^6 就肯定够了(如果操作次数>10^6,n*log(n)可能要超时)

代码
Treap

#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
int n,k,p;
struct nod{
    nod *s[2];
    int k,p,r;
    nod(int k1,int p1,int r1){s[0]=s[1]=NULL;k=k1;p=p1;r=r1;}
}*rot;
int read()
{
    int ret=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
int rd(){return rand()<<16|rand()<<1|(rand()&1);}
void rotate(nod* &x,int p)//把x转动到x的p儿子的位置 
{
    nod *y=x->s[p^1];
    if (y==NULL) return;
    x->s[p^1]=y->s[p];
    y->s[p]=x;
    x=y;
}
void insert(nod* &x,int k,int p)
{
    if (x==NULL) {x=new nod(k,p,rd());return;}
    int d=p>x->p;
    insert(x->s[d],k,p);
    if (x->s[d]->r>x->r) rotate(x,d^1);
}
void del(nod* &x)
{
    if (x->s[0]==NULL) x=x->s[1];else
    if (x->s[1]==NULL) x=x->s[0];else
    {
        int d=(x->s[0]->r>x->s[1]->r)?1:0;
        rotate(x,d);del(x->s[d]);
    }
}
bool fin(nod* &x,int f)//z=0表示最小,z=1表示最大 
{
    if (x==NULL) return 1;
    if (fin(x->s[f],f)) {printf("%d\n",x->k);del(x);return 0;}
    return 0;
}
int main()
{
    srand((unsigned int)(time(NULL)));
    while (n=read())
      if (n==1) {k=read();p=read();insert(rot,k,p);}else if (fin(rot,n==2)) printf("0\n");
    return 0;
}

#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
const int maxn=1e6+6;
struct js{
    int k,p;
    bool operator <(const js b)const{return p<b.p;}
    bool operator >(const js b)const{return p>b.p;}
}h[2][maxn];
int n,tot[2],k,p;
bool vis[maxn];
int put(int o,int k,int p)
{
    h[o][++tot[o]]=(js){k,p};
    if (o) push_heap(h[o]+1,h[o]+tot[o]+1);
      else push_heap(h[o]+1,h[o]+tot[o]+1,greater<js>());
}
int get(int o)
{
    if (o) pop_heap(h[o]+1,h[o]+tot[o]+1);
      else pop_heap(h[o]+1,h[o]+tot[o]+1,greater<js>());
    return h[o][tot[o]--].k;
}
int main()
{
    while (1)
    {
        scanf("%d",&n);
        if (n==0) break;
        if (n==1)
        {
            scanf("%d%d",&k,&p);
            vis[k]=0;
            put(0,k,p);put(1,k,p);
        }else if (n==2)
        {
            while (tot[1]>0&&vis[h[1][1].k]) get(1);
            if (tot[1]>0) vis[h[1][1].k]=1,printf("%d\n",get(1));
            else printf("0\n");
        }else
        {
            while (tot[0]>0&&vis[h[0][1].k]) get(0);
            if (tot[0]>0) vis[h[0][1].k]=1,printf("%d\n",get(0));
            else printf("0\n");
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值