算法实验题8.1 黑箱子问题
★问题描述:
黑箱子是一个数据库,它能存放很多记录,每条记录包含一个整数,它有一个索引值index,它还能处理两种命令:
(1) append x: 将记录x添加到黑箱子中
(2) print: 将索引值加1,然后输出黑箱子里所有记录中第index小的记录,初始时刻黑箱子是空的并且索引值为0.设计实现黑箱子的算法
★实验任务:
对于给定的append运算和print运算组成的命令序列,计算print命令的输出序列
★数据输入:
第1行有1个正整数n(1<=n<=70000)表示命令数,接下来n行每行有一条命令
★结果输出:
黑箱子是一个数据库,它能存放很多记录,每条记录包含一个整数,它有一个索引值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; }
新 blog : www.hrwhisper.me