hdu 2852 KiKi's K-Number 二分+树状数组

http://acm.hdu.edu.cn/showproblem.php?pid=2852

题意:给出三种操作,
    0 在容器中插入一个数。
    1 在容器中删除一个数。
    2 求出容器中大于a的第k大元素。

思路:二分+树状数组

树状数组的特点就是对点更新,成段求和,而且常数非常小。原始
的树状数组只有两种操作,在某点插入一个数 和 求1到i的所有数的和。
这道题目一共有三种操作,但是实质上其实只有两种:插入和询问。插入
操作和删除操作可以视为一种,只不过一个是将标记+1,另一个是-1,而
插入的数对应于树状数组的下标,这样就可以在log(n)的时间内完成插入
和删除。求大于a的k大元素,可以通过二分枚举答案来完成,枚举的是当
前答案在树状数组中的位置,设为m,然后对v[a+1]  v[m]求和就是小
于等于m的数的个数,这一步可以用树状数组的求和操作来完成,然后根据
和k的比较来调整m的位置。询问的复杂度也是log(n)的。

以上转自:http://www.cppblog.com/menjitianya/archive/2011/03/31/143100.html

代码:

#include<stdio.h>
#include<string.h>
const int MAXN = 100010 ;
int Q ;
int C[MAXN] ;
int num[MAXN] ;

int lowbit(int i){
	return i & ( -i ) ;
}
void add(int i, int a){
	while(i < MAXN){
		C[i] += a ;
		i += lowbit(i) ;
	}
}
int sum(int i){
	int res = 0 ;
	while(i >= 1){
		res += C[i] ;
		i -= lowbit(i) ;
	}
	return res ;
}
void Bsearch(int a, int k){
	int low = a + 1, high = MAXN - 1 ;
	int res1 = sum(a) ;
	while(low < high){
		int mid = (low + high) >> 1 ;
		int res2 = sum(mid) ;
		if(res2 - res1 < k){
			low = mid + 1 ;
		}
		else{
			high = mid ;
		}
	}
	if(low == MAXN -1){
		printf("Not Find!\n");
	}
	else
		printf("%d\n",low); 
}
int main(){
	int a,b,c; 
	while(scanf("%d",&Q) == 1){
		memset(C, 0 ,sizeof(C));
		memset(num, 0 ,sizeof(num));
		for(int i=0;i<Q;i++){
			scanf("%d",&a);
			if(a==0){
				scanf("%d",&b) ;
				num[b]++ ;
				add(b,1) ;
			}
			else if(a == 1){
				scanf("%d",&b);
				if(num[b] == 0){
					printf("No Elment!\n");
					continue ;
				}
				num[b] -- ;
				add(b,-1) ;
			}
			else{
				scanf("%d%d",&b,&c) ;
				Bsearch(b,c);
			}
		}
		
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值