黑箱子是一个数据库,它能存放很多记录,每条记录包含一个整数,它有一个索引值index,它还能处理两种命令:
(1) append x: 将记录x添加到黑箱子中
(2) print: 将索引值加1,然后输出黑箱子里所有记录中第index小的记录,初始时刻黑箱子是空的并且索引值为0.设计实现黑箱子的算法
★实验任务:
对于给定的append运算和print运算组成的命令序列,计算print命令的输出序列
★数据输入:
第1行有1个正整数n(1<=n<=70000)表示命令数,接下来n行每行有一条命令
★结果输出:
将计算出的print运算的输出序列输出
输入示例
15
append 1
print
append 7
append 2
print
append 3
append 6
print
append 9
append 4
print
append 8
append 5
print
append 10
输出示例
1 2 3 4 5
和上次的神谕者。。呵呵呵呵。
神谕者的代码改改估计就可以了。数据结构与算法实验题 10.1 神谕者
不过也可以维护一个第k小的堆
代码等12月2号贴上。
一、最大最小堆
当操作为插入的时候,如果待插入的元素x 比最大堆的元素小,说明第k个最小值可能是最大堆的堆顶,把最大堆的堆顶删除移动到最小堆,那个x插入到最大堆。
当然一开始的时候直接插入最小堆。
然后查询的时候直接输出最小堆堆顶,然后把最小堆堆顶删除并转移到最大堆、
这样做保证最大堆堆顶<最小堆堆顶,所以最小堆堆顶一定是解
#include<cstdio>
const int MAXN=70000+1;
struct heap
{
int min_tree[MAXN];
int max_tree[MAXN];
int min_cur_size;
int max_cur_size;
heap(){max_cur_size=min_cur_size=0;}
void min_matain(int hole)
{
int child;
int temp=min_tree[ hole ];
for(;( hole <<1 ) <=min_cur_size ; hole=child)
{
child= (hole << 1);
if(child != min_cur_size && min_tree[child + 1 ] < min_tree [child] )
child++;
if(min_tree[child] <temp)
min_tree[hole]=min_tree[child];
else
break;
}
min_tree[hole]=temp;
}
void max_matain(int hole)
{
int child;
int temp=max_tree[ hole ];
for(;( hole <<1 ) <=max_cur_size ; hole=child)
{
child= (hole << 1);
if(child != max_cur_size && max_tree[child + 1 ] > max_tree [child] )
child++;
if(max_tree[child] >temp)
max_tree[hole]=max_tree[child];
else
break;
}
max_tree[hole]=temp;
}
int min_top()
{
return min_tree[ 1 ];
}
int max_top()
{
return max_tree[1];
}
void min_pop()
{
min_tree[1]=min_tree[min_cur_size--];
min_matain(1);
}
void max_pop()
{
max_tree[1]=max_tree[max_cur_size--];
max_matain(1);
}
void min_push(int x)
{
int hole=++min_cur_size;
for(; hole >1 && x < min_tree [(hole >>1)];hole>>=1)
{
min_tree[hole] = min_tree [ hole >> 1];
}
min_tree[hole]=x;
}
void max_push(int x)
{
int hole=++max_cur_size;
for(; hole >1 && x > max_tree [(hole >>1)];hole>>=1)
{
max_tree[hole] = max_tree [ hole >> 1];
}
max_tree[hole]=x;
}
}q;
int main()
{
int n,i;
scanf("%d",&n);
int k=0,temp;
char cmd[20];
for(i=0;i<n;i++)
{
scanf("%s",cmd);
if(cmd[0]=='a')
{
scanf("%d",&temp);
if(i==0)
{
q.min_push(temp);
continue;
}
if(temp < q.max_top())
{
q.min_push(q.max_top());
q.max_pop();
q.max_push(temp);
}
else
q.min_push(temp);
}
else
{
k++;
int kth=q.min_top();
q.min_pop();
printf("%d ",kth);
q.max_push(kth);
}
}
printf("\n");
return 0;
}
二、SBT修改一下。
#include<cstdio>
const int MAXN=200000+10;
struct SBT
{
int left[MAXN]; //left son
int right[MAXN]; //right son
int size[MAXN]; //the num of sons
int value[MAXN]; //value
int len; //length
int root;
SBT(){ root=len=0; }
void right_rotate(int &t)
{
int k=left[t];
left[t]=right[k];
right[k]=t;
size[k]=size[t];
size[t]=size[ left[t] ] + size[ right[t] ] +1;
t=k;
}
void left_rotate(int &t)
{
int k=right[t];
right[t]=left[k];
left[k]=t;
size[k]=size[t];
size[t]=size[left[t]]+size[right[t]]+1;
t=k;
}
void insert(int &t,int v)
{
if(!t)
{
t=++len;
value[t]=v;
size[t]=1;
left[t]=right[t]=0;
return;
}
size[t]++;
if(v < value[t])
insert(left[t],v);
else
insert(right[t],v);
matain(t);
}
void matain(int &t)
{
if(size[ left[ left[t] ] ] > size[ right[t] ] )
{
right_rotate(t);
matain(right[t]);
matain(t);
}
else if( size[ right[ left[t] ] ]>size[ right[t] ] )
{
left_rotate(left[t]);
right_rotate(t);
matain(left[t]);
matain(right[t]);
matain(t);
}
else if(size[ right[ right[t] ] ]>size[ left[t] ])
{
left_rotate(t);
matain(left[t]);
matain(t);
}
else if(size[ left[ right[t] ] ]>size[ left[t] ])
{
right_rotate(right[t]);
left_rotate(t);
matain(left[t]);
matain(right[t]);
matain(t);
}
}
int select(int t,int k)
{
if(k==size[left[t]]+1)
return value[t];
if(k<=size[left[t]])
return select(left[t],k);
else
return select(right[t],k-size[left[t]]-1);
}
}sbt;
int main()
{
int n,i;
scanf("%d",&n);
int k=0,temp;
char cmd[20];
while(n--)
{
scanf("%s",cmd);
if(cmd[0]=='a')
{
scanf("%d",&temp);
sbt.insert(sbt.root,temp);
}
else
{
k++;
printf("%d ",sbt.select(sbt.root,k));
}
}
printf("\n");
return 0;
}
三、划分树修改。。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXM=20;
const int MAXN=70000+10;
int data[MAXM][MAXN], num[MAXM][MAXN], sorted[MAXN];
struct node
{
int kind; //kind=0 代表插入 kind=1则为查询
}p[MAXN];
void Build(int depth, int L, int R) {
if (L == R)
return;
int same, mid, i, left, right;
mid = (L + R) >> 1;
same = mid - L + 1;
left = L;
right = mid + 1;
for (i = L; i <= R; i++) {
if (data[depth][i] < sorted[mid])
same--;
}
//same用来标记和中间值val_mid 相等的,且分到左孩子的数的个数。
for (i = L; i <= R; i++) {
if (data[depth][i] < sorted[mid])
data[depth + 1][left++] = data[depth][i];
else if (data[depth][i] == sorted[mid] && same) {
data[depth + 1][left++] = data[depth][i];
same--;
} else
data[depth + 1][right++] = data[depth][i];
num[depth][i] = num[depth][L - 1] + left - L;
//num记录元素所在区间的当前位置之前进入左孩子的个数
}
Build(depth + 1, L, mid);
Build(depth + 1, mid + 1, R);
}
int findk(int L, int R, int x, int y, int k,int depth) {
if (L == R)
return data[depth][L];
int mid, left, temp;
mid = (L + R) >> 1;
left = num[depth][y] - num[depth][x - 1];
temp = num[depth][x - 1] - num[depth][L - 1];
if (left >= k)
return findk( L, mid, L + temp, L + temp + left - 1, k,depth + 1);
else {
k -= left;
temp = x - L - temp;
left = y - x + 1 - left;
return findk( mid + 1, R, mid + temp + 1, mid + temp + left, k,depth + 1);
}
}
int main() {
int n,i;
int len=0,temp;
scanf("%d", &n);
char cmd[20];
for(i=0;i<n;i++)
{
scanf("%s",cmd);
if(cmd[0]=='a')
{
scanf("%d",&temp);
p[i].kind=0;
len++;
sorted[len] = data[0][len] = temp;
}
else if(cmd[0]=='p')
{
p[i].kind=1;
}
}
sort(sorted + 1, sorted + len + 1);
Build(0, 1, len);
int cnt=0; //统计当前元素个数
int k=0;
for(i=0;i<n;i++)
{
if(p[i].kind==0)
cnt++;
else
{
k++;
printf("%d ",findk(1,len,1,cnt,k,0));
}
}
printf("\n");
return 0;
}