黑匣子
(box.pas/c/cpp)
【 问题描述】
某研究小组成员想发明一个黑匣子( 当然不是飞机上那个), 而是一个具有特殊功能的箱子。 这个箱子具有两个功能: 1. 存放一些正整数 x; 2. 对于第 k 次询问, 它会告诉你箱子中第 k 小的数字是多少。 但光具有理论是不够的, 理论往往应联系实际。 这可是一个大大的难题, 没有丰富程序设计知识的同学们希望你能帮助他们写出这个程序代码, 以便他们能完成黑匣子的制作。
【 输入格式】
第一行, 一个数字 n 表示对黑匣子的操作次数。
以下 n 行, 每行一个数字。 若这个数字是正整数, 则表示在黑匣子中添加这个数字;
若这个数字是1, 这表示一次询问。
【 输出格式】
若干行, 对应每次询问所得的结果( 必定存在答案)
【 样例输入】
8
1
-1
8
8
-1
5
-1
-1
【 样例输出】
1
8
8
8
【 样例说明】
第一次询问时, 黑匣子内为 1, 输出最小的数 1;
第二次询问时, 黑匣子内为 1 8 8, 输出第二小的数 8;
第三次询问时, 黑匣子内为 1 5 8 8, 输出第三小的数 8;
第四次询问时, 黑匣子内为 1 5 8 8, 输出第四小的数 8。
【 数据范围】
对于30%的数据, 5<=n<=200
对于60%的数据, 5<=n<=10000
对于100%的数据, 5<=n<=100000, n为整数, x为不超过maxlongint的正整数。
这是一道典型的二叉搜索树(平衡树)的题目,但是我们也能用二叉堆的方法来过这道题。//膜拜Y’ADs
首先我们新建两个堆,一个是大根堆,一个是小根堆。
大根堆用于存储前K小个数,小根堆则用于存储其他数.
那么怎样来操作呢?
每读入一个数,与大根堆的TOP(堆头)比较,如果比它小,那么把大根堆的TOP放入小根堆,再将读入的数放入大根堆,即交换。
输出只需要输出小根堆TOP就好了。
再将输出的数从小根堆放入大根堆。
那么我来解释一下为什么可以这样操作。
首先我们已知的两个堆中,大根堆的所有数一定小于小根堆的所有数。大根堆中的数正是前K个数。
接着读入的数如果大于大根堆的TOP,那么这个数就比第K小的数大,只需要放入小根堆就成了(在读入-1时输出)。
但如果它小于大根堆的TOP,证明它小于第K小数。所以把大根堆的数取出来,将读入的数放进去。再将取出的数放入小根堆(在读入-1时输出)。
code:
priority_queue <int,vector<int>,greater<int> > x1; priority_queue <int>x2; for(i=1;i<=n;i++) { int x=read(),y; if(x==-1) { y=x1.top(); printf("%d ",y); x2.push(y); x1.pop(); } else { if(!x2.empty()) { y=x2.top(); if(x<y){x2.pop();x2.push(x);x1.push(y);} else x1.push(x); } else x1.push(x); } }
O(NlogN)