您的位置:首页 > 产品设计 > UI/UE

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;

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  build query struct