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