HZOI 10-17 problem1 用堆求第k大

题意很明白 正解应该是维护一颗二叉查找树 但是那玩意太难写 所以就出现了民间解法

建一个小根堆 一个大根堆 

保证小根堆里的数都比大根堆里的大

当大根堆里元素个数为K时 大根堆堆顶元素就是第K小的 (第K大类似)

当添加一个元素时如果它比大根堆堆顶的元素小说明它应该插入大根堆(保证小根堆里的数都比大根堆里的大)

反之加入小根堆

当我们差第K小的元素时 就保证大根堆里只有K个  取堆顶就好

这种做法据说可以水完 但我没有可能哪儿写残了

#include <iostream>
#include <stdio.h>
#include <cstdlib>
#define FOR( x , y ) for( int p = x ; p <= y ; p ++ )
using namespace std ; 

int n ;

struct X{
	int dui[ 250005 ] , top ; 
	void put( int x ) {
		dui[ ++ top ] = x ; 
		int now = top , next ; 
		while( now > 1 ) {
			
			next = now >> 1 ; 
			if( dui[ next ] <= dui[ now ] ) break ; 
			swap( dui[ next ] , dui[ now ] ) ; 
			now = next ;  
		}
	}
	int get( ) {
		int res = dui[ 1 ] , now = 1 , next ; dui[ 1 ] = dui[ top -- ] ; 
		while( now << 1 <= top ) {
			next = now << 1 ;
			if( dui[ next + 1 ] < dui[ next ] ) next ++ ; 
			if( dui[ now ] <= dui[ next ] ) break ; 
			swap( dui[ now ] , dui[ next ] ) ; 
			now = next ; 
		}
		return res ; 
	}
} xd ;

struct D{
	int dui[ 250005 ] , top ; 
	void put( int x ) {
		dui[ ++ top ] = x ; 
		int now = top , next ; 
		while( now > 1 ) {
			next = now >> 1 ; 
			if( dui[ next ] >= dui[ now ] ) break ; 
			swap( dui[ next ] , dui[ now ] ) ; 
			now = next ;  
		}
	}
	int get( ) {
		int res = dui[ 1 ] , now = 1 , next ; dui[ 1 ] = dui[ top -- ] ;
		while( now << 1 <= top ) {
			next = now << 1 ;
			if( dui[ next + 1 ] > dui[ next ] ) next ++ ; 
			if( dui[ now ] >= dui[ next ] ) break ; 
			swap( dui[ now ] , dui[ next ] ) ; 
			now = next ; 
		}
		return res ; 
	}
} dd ;

int cx( ) {
	if( dd . top == 0 ) return 0 ; 
	else return dd . dui[ 1 ] ; 
}

int main( ) {
	
	freopen( "problem1.in" , "r" , stdin ) ; 
	freopen( "problem1.out" , "w" , stdout ) ; 
	
	char a ; int b , ges = 0 ; 
	scanf( "%d" , &n ) ; getchar( ) ; 
	FOR( 1 , n ) {
		scanf( "%c%d" , &a , &b ) ; getchar( ) ; 
		if( a == 'i' ) {
			ges ++ ; 
			if( b <= cx( ) ) dd . put( b ) ; 
			else xd . put( b ) ; 
		}
		else {
			b = ges - b + 1 ;
			while( dd . top < b ) dd . put( xd . get( ) ) ; 
			while( dd . top > b ) xd . put( dd . get( ) ) ; 
			cout << dd . dui[ 1 ] << endl ; 
		} 
	}
	return 0 ; 
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值