任务调度(Schedule)

任务调度(Schedule)

Description

A HPS cluster is equipped with a unique task scheduler. To be simple, it is assumed that this cluster doesn’t support multiple tasks running at the same time, such that only one task is allowed to be in running state at any moment. Initially, the priority of ever task is denoted by an integer which is called priority number. The smaller priority number stands for high priority. If two tasks have same task number, the priority is decided in the ASCII order of task name. Following this policy, resources, such as CPU, are always occupied by the task with minimum priority number. When one task is finished, the one with minimum priority number in the rest tasks is picked to execute. The finished task won’t quit immediately. The priority number is doubled and put back to the task set. Once the priority number is greater or equal to 2^32, this task is deleted from the task set.

Given initial priority setting of every task, your job is to predict the running order of a batch of tasks.

Input

First line contains two integers, says n and m. n stands for the number of tasks in initial state. m stands for the length of predicted sequence. Every line is ended by a line break symbol. In each one of the following n lines, an integer and a string are included. This string is shorter than 8, which only contains lowercase letters and numbers. The integer is priority number and the string is the task name. The integer and string is separated by space.

Output

At most m lines, each one contains a string. Output the name of tasks according to the order that tasks are executed. If the number of executed tasks is less than m, then output all the executed tasks.

Example

Input

3 3
1 hello
2 world
10 test

Output

hello
hello
world

Restrictions

0 <= n <= 4,000,000

0 <= m <= 2,000,000

0 < Initial priority number < 2^32

No tasks have same name

Time: 2 sec

Memory: 512 MB

Hints

Priority queue

  1. 原理与要点:题意就是非常简单的优先队列的应用,由于没有STL,需要手写一个实现一个小根堆。每次取出堆顶,输出,然后将其优先级数乘以2,如果优先级数小于\(2^{32}\),则重新入队。直至执行m次取出操作或队为空。
  • 小根堆的原理与要点
    • insert:insert(val)操作向二叉堆中插入一个带有权值val的新节点。直接把这个新节点放在存储二叉堆的数组末尾,然后通过交换的方式向上调整,直至满足堆性质。其时间复杂度为堆的深度,即\(O(logn)\)
    • extract: extract操作把堆顶从二叉堆中移出。把堆顶heap[1]与存储在数组末尾的节点heap[n]交换,然后移除数组末尾节点(令n减小1),最后把堆顶通过交换的方式向下调整,直至满足堆性质。其时间复杂度为堆的深度,即\(O(logn)\)
  1. 遇到的问题:
  2. 时间和空间复杂度:时间复杂度\(O((m+n)logn)\), 空间复杂度\(O(n)\)
#include "iostream"
#include "cstring"
#include "cmath"

using namespace std;
const int maxn = 1e7;
typedef long long ll;
const int SZ = 1<<20;  //快速io
struct fastio{
    char inbuf[SZ];
    char outbuf[SZ];
    fastio(){
        setvbuf(stdin,inbuf,_IOFBF,SZ);
        setvbuf(stdout,outbuf,_IOFBF,SZ);
    }
}io;
struct node {
    ll val;
    char str[10];

    friend bool operator<(node a, node b) {
        if (a.val != b.val)
            return a.val < b.val;
        return strcmp(a.str, b.str) < 0;
    }
} heap[maxn];

int n = 0;

void up(int p) {
    while (p > 1) {
        if (heap[p] < heap[p / 2]) {
            swap(heap[p], heap[p / 2]);
            p /= 2;
        } else break;
    }
}

void down(int p) {
    int s = p * 2;
    while (s <= n) {
        if (s < n && heap[s+1] < heap[s]) s++;
        if (heap[s] < heap[p]) {
            swap(heap[p], heap[s]);
            p = s;
            s *= 2;
        } else break;
    }
}

void extract() {
    heap[1] = heap[n--];
    down(1);
}

void insert(node val) {
    heap[++n] = val;
    up(n);
}


int main() {
//    freopen("in.txt", "r", stdin);
    int a, b;
    node x;
    scanf("%d %d", &a, &b);
    ll p = 1;
    for (int i = 0; i < 32; i++) {
        p *= 2;
    }
    for (int i = 0; i < a; i++) {
        scanf("%lld %s", &x.val, x.str);
        insert(x);
    }
    while (b-- && n >= 1) {
        printf("%s\n", heap[1].str);
        x = heap[1];
        x.val *= 2;
        extract();
        if (x.val < p) {
            insert(x);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值