题意:先输入两个整数 n, k。然后有 n 行输入, I 代表写下一个数字, Q代表询问在所有写下的数字中第 k 大的数数多少?
题解:因为当写下的数少于 k 个是不存在询问的情况。所以可以建一个堆,然后没写下一个数字,若它比堆中的最小数字还小,则堆不做改变。若它比堆中的最小数字要大,那么将堆中的最小数字去掉,并加入刚写入的数字。
具体写了三种方法:
方法一:最小堆
#include <algorithm> #include <iostream> using namespace std; struct min_Heap { int array[1000002], size; void siftDown ( int start ) //下滑调整,若子女的值小于父节点的值,则子节点上浮,之后继续向下层比较 { int i = start, j = i * 2; int temp = array[start]; while ( j <= size ) { if ( j < size && array[j] > array[j+1] ) ++j; if ( temp <= array[j] ) break; else { swap(array[i],array[j]); i = j; j = j * 2; } } } void siftUp ( int start ) //上滑调整,若子女的值小于父节点的值则互相交换 { int j = start, i = j / 2; int temp = array[j]; while ( j >= 1 ) { if ( temp >= array[i] ) break; else { swap(array[i],array[j]); j = i; i = i / 2; } } } void build_minHeap () //建堆 { int current = size / 2; while ( current >= 1 ) { siftDown ( current ); current--; } } } minHeap; int main() { char oper[3]; int n, k, num; while ( scanf("%d%d",&n,&k) != EOF ) { minHeap.size = 0; for ( int i = 1; i <= n; i++ ) { scanf("%s",oper); if ( oper[0] == 'I' ) { scanf("%d",&num); if ( minHeap.size < k ) { minHeap.size++; minHeap.array[minHeap.size] = num; if ( minHeap.size == k ) minHeap.build_minHeap (); } else if ( num > minHeap.array[1] ) { minHeap.array[1] = num; minHeap.siftDown ( 1 ); } } else printf("%d\n",minHeap.array[1]); } } return 0; }
#include <queue> #include <iostream> using namespace std; int main() { char oper[3]; int n, k, num; while ( scanf("%d%d",&n,&k) != EOF ) { priority_queue< int,vector<int>,greater<int> > que; for ( int i = 1; i <= n; i++ ) { scanf("%s",oper); if ( oper[0] == 'I' ) { scanf("%d",&num); if ( que.size() < k ) que.push(num); else { if ( num > que.top() ) { que.pop(); que.push(num); } } } else printf("%d\n",que.top() ); } } return 0; }
方法三:线段树实现。线段树的实现效率虽然比以上两种略差,但是实用性很强。更容易拓展。
#include <algorithm> #include <iostream> using namespace std; #define L(u) ( u << 1 ) #define R(u) ( u << 1 | 1 ) #define N 1000001 struct item { int l, r, v; } node[N*3]; void build ( int u, int l, int r ) { node[u].l = l; node[u].r = r; node[u].v = 0; if ( l == r ) return; int mid = ( l + r ) >> 1; build ( L(u), l, mid ); build ( R(u), mid+1, r); } void update ( int u, int pos ) { node[u].v++; if ( node[u].l == pos && node[u].r == pos ) return; int mid = ( node[u].l + node[u].r ) >> 1; if ( pos <= mid ) update ( L(u), pos ); else update ( R(u), pos ); } int query ( int u, int k ) { if ( node[u].l == node[u].r ) return node[u].l; if ( k <= node[L(u)].v ) return query ( L(u), k ); else return query ( R(u), k - node[L(u)].v ); } int main() { char oper[3]; int n, k, num, cnt; while ( scanf("%d%d",&n,&k) != EOF ) { cnt = 0; build ( 1, 1, 1000000 ); for ( int i = 1; i <= n; i++ ) { scanf("%s",oper); if ( oper[0] == 'I' ) { scanf("%d",&num); cnt++; /* cnt 统计一共写下的数字 */ update ( 1, num ); } else printf("%d\n", query(1,cnt-k+1) ); /* 注意是 cnt-k+1 */ } } return 0; }