【ACM专题训练】二叉树和堆

任务系统

蒜头君设计了一个任务系统。这个系统是为了定时提醒蒜头君去完成一些事情。

系统大致如下,初始的时候,蒜头君可能会注册很多任务,每一个任务的注册如下:

Register Q_num Period

表示从系统启动开始,每过 Period 秒提醒蒜头君完成编号为Qnum​ 的任务。

你能计算出蒜头君最先被提醒的 k 个任务吗?

输入格式

第一行输入 n(0<n≤50000),k(0<k≤10000),其中 n 表示蒜头君注册的任务数量。

接下来 n 行,每行输入一条注册命令,其中0<qnum​≤3000,0≤Period≤3000。

输出格式

顺序输出 k 行,表示依次提醒的任务的编号。如果同一时间有多个任务,最先提醒编号小的任务。

样例输入复制

2 5
Register 2004 200
Register 2005 300

样例输出复制

2004
2005
2004
2004
2005

思路:优先队列实现

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
struct task{
    int num;
    int period;
    int t;
    bool operator <(const task other) const{
        if(t != other.t){
            return t > other.t;
        }
        else 
            return num > other.num;
    }
};    
priority_queue<task> pq;
int main(){
    int n,k;
    int tnum,tperiod;
    task tmp;
    string s;
    cin >> n >> k;
    while(n--){
        cin >> s >> tnum >> tperiod;
        tmp.num = tnum;
        tmp.period = tperiod;
        tmp.t = tmp.period;
        pq.push(tmp);
    }
    while(k--){
        tmp = pq.top();
        pq.pop();
        cout << tmp.num << endl;
        tmp.t += tmp.period;
        pq.push(tmp);
    }
    return 0;
}

n个最小和

给出两个包含 n 个整数的数组 A,B。分别在 A, B 中任意出一个数并且相加,可以得到 n^2 个和。求这些和中最小的 n 个。

输入格式

输入第一行一个整数 n(1≤n≤50000)。

接下来一行输入数组 A,用空格隔开。

接下来一行输入数组 B,用空格隔开。

1≤Ai​,Bi​≤10^9

输出格式

从小到大输出最小的 n 个和,用空格隔开。

样例输入复制

4
1 3 5 7
2 4 6 8

样例输出复制

3 5 5 7
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int aa[50002],bb[50002];
struct node{
    int a;
    int b;
    int sum;
    bool operator <(const node other) const{
        return sum > other.sum;
    }
};
priority_queue<node> pq;
int main(){
    int n ;
    cin >> n;
    for(int i  = 0;i < n;i++){
        cin >> aa[i];
    }
    for(int i  = 0;i < n;i++){
        cin >> bb[i];
    }
    sort(aa,aa+n,less<int>());
    sort(bb,bb+n,less<int>());
    for(int i  = 0;i < n;i++){
        node tmp;
        tmp.a = i;
        tmp.b = 0;
        tmp.sum = aa[i] + bb[0];
        pq.push(tmp);
    }
	for(int i  = 0;i < n;i++){
        node t = pq.top();
        pq.pop();
        if(!i){
            cout << t.sum;
        }
        else{
            cout << " " << t.sum;
        }
        t.b++;
        t.sum = aa[t.a] + bb[t.b];
        pq.push(t);
        
    }
    return 0;
}

银行的客户队列

某个银行很傲娇,来了一些客户,有时先接待优先级最高的客户,有时先接待优先级最低的客户,有如下四种操作:

0:系统停止服务。

1 K P:增加一个 ID 为 K(K≤106) 的客户,其优先级是 P(P≤107)。

2:查询优先级最高的客户,接待他,并从等候队列里删除。

3:查询优先级最低的客户,接待他,并从等候队列里删除。

你的任务是依次输出这些客户的 ID。

输入格式

若干行,以 0 结束(总操作数不超过 10^5)。

一个客户可能访问多次;保证在任意时刻,队列中的优先级各不相同。

输出格式

对于 2 和 3 操作,一行一个整数表示 ID,若查询无结果,则输出 0。

样例输入复制

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

样例输出复制

0
20
30
10
0

思路:stl中的set会自动排序

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <queue>
#include <set>
using namespace std;
set<pair<int,int> > q;
//pair按第一维排序从小到大,再按第二维从小到大
int main(){
    int op,k,p;
    set<pair<int,int> >::iterator it;
    while(cin >> op && op){
        if(op == 1){
            cin >> k >> p;
            q.insert(make_pair(p,k));
        }
        else if(op == 2){
            if(q.empty()){
                cout << 0 << endl;
            }
            else{
                it = q.end();
                it--;
                cout << it->second << endl;
                q.erase(it);
            }            
        }
        else{
            if(q.empty()){
                cout << 0 << endl;
            }
            else{
                it = q.begin();
                cout << it->second << endl;
                q.erase(it);                
            }
        }
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值