HDU 4006 The kth great number 堆/优先级队列/线段树
2011-09-05 16:48
579 查看
题意:先输入两个整数 n, k。然后有 n 行输入, I 代表写下一个数字, Q代表询问在所有写下的数字中第 k 大的数数多少?
题解:因为当写下的数少于 k 个是不存在询问的情况。所以可以建一个堆,然后没写下一个数字,若它比堆中的最小数字还小,则堆不做改变。若它比堆中的最小数字要大,那么将堆中的最小数字去掉,并加入刚写入的数字。
具体写了三种方法:
方法一:最小堆
方法二:优先级队列。其实和上面一种方法没有本质区别
方法三:线段树实现。线段树的实现效率虽然比以上两种略差,但是实用性很强。更容易拓展。
#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;
}
题解:因为当写下的数少于 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;
}
相关文章推荐
- hdu 4006 The kth great number 优先级队列
- HDU 4006 The kth great number(优先队列、堆实现)
- hdu 4006 The kth great number 很复杂的线段树,至少对于我来说,但也学会了很多!!!!!!!!!!
- HDU 4006 The kth great number【优先队列】
- hdu 4006 The kth great number(线段树单点更新)
- HDU 4006 The kth great number (堆实现优先队列)
- HDU 4006 The kth great number【优先队列】
- HDU 4006 The kth great number 【优先队列求第K大数】
- HDU 4006 The kth great number 优先队列、平衡树模板题(SBT)
- HDU 4006 The kth great number(线段树【亚洲区网络赛题目】)
- hdu 4006 The kth great number(线段树 || 优先队列)
- HDU Problem 4006 The kth great number 【队列】
- HDU 4006 The kth great number 【队列】
- hdu 4006 The kth great number 线段树
- HDU 4006 The kth great number【线段树二分】
- 【HDU】-4006-The kth great number(优先队列,好)
- hdu 4006 The kth great number
- hdu 4006 The kth great number (优先队列)
- hdu 4006 The kth great number(优先队列)
- HDU4006(The kth great number)优先级队列/SBT