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

这题就是给了你三种操作,

1:往容器中一个元素 x

2::把容器中的元素x删除

3:查询比 x大的第k个数

想法:添加元素跟删除元素  直接是以数本身为序号然后以 value值为1和-1即可,相当于计数,至于找比x第k个大的数,那就看看当前往后数k个数的第一个数是哪个就可以了,一开始直接找出来,然后往后暴力的扫了一遍,结果错了,没关系,反应很快,直接改了个二分查找,然后就过了,弄清楚如何建立这个树状数组即可

#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>
#include<cctype>

#define ll long long
#define LL __int64
#define eps 1e-8

//const ll INF=9999999999999;

#define inf 0xfffffff

using namespace std;

//vector<pair<int,int> > G;
//typedef pair<int,int> P;
//vector<pair<int,int>> ::iterator iter;
//
//map<ll,int>mp;
//map<ll,int>::iterator p;

const int N = 100000 + 10;

int n;

int c[N];

void clear() {
	memset(c,0,sizeof(c));
}

int lowbit(int x) {
	return x&(-x);
}

//设原始矩阵为a,将a[i]加上val时对c所做的修改
void add(int i, int val) {
	while (i <= N) {
		c[i] += val;
		i += lowbit(i);
	}
} 

//求前i项元素的和
int get_sum(int i) {
	int sum = 0;
	while (i > 0) {
		sum += c[i];
		i -= lowbit(i);
	}
	return sum;
}

void cal(int a,int k) {
	int sum = get_sum(a);
	bool flag = false;
	int l = a + 1;
	int r = N;
	while(l < r) {
		int mid = (l + r)/2;
		int tmp = get_sum(mid);
		if(tmp < sum + k)
			l = mid + 1;
		else
			r = mid;
	}
	if(get_sum(l) >= k + sum) {
		printf("%d\n",l);
	}
	else
		puts("Not Find!");
}

int main() {
	int n;
	while(scanf("%d",&n) == 1) {
		clear();
		int x;
		for(int i=0;i<n;i++) {
			scanf("%d",&x);
			if(x == 0) {
				int y;
				scanf("%d",&y);
				add(y,1);
			}
			if(x == 1) {
				int y;
				scanf("%d",&y);
				if(get_sum(y) == get_sum(y - 1))
					puts("No Elment!");
				else
					add(y,-1);
			}
			if(x == 2) {
				int a,k;
				scanf("%d %d",&a,&k);
				cal(a,k);
			}
		}
	}
	return 0;
}

HDU2852 KiKi's K-Number 树状数组+二分,码迷,mamicode.com

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

时间: 2024-10-11 08:24:40

HDU2852 KiKi's K-Number 树状数组+二分的相关文章

hdu-2852 KiKi&#39;s K-Number---二分+树状数组

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2852 题目大意: 题意:    给出三种操作,    0 在容器中插入一个数.    1 在容器中删除一个数.    2 求出容器中大于a的第k大元素. 解题思路: 用树状数组维护每个值,插入数字是add(x, 1),删除时add(x, -1) 查询第k大时,先判断是否存在,存在的话直接根据树状数组sum值的单调性二分法求解即可 1 #include<iostream> 2 #include&l

HDU 2852 KiKi&#39;s K-Number(树状数组+二分)

KiKi's K-Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2598    Accepted Submission(s): 1199 Problem Description For the k-th number, we all should be very familiar with it. Of course,t

HDU 2852 KiKi&#39;s K-Number【 树状数组 二分 】

题意:给出m个操作,0:是增加一个数,add(x,1)1:是删除一个指定的数,这个是看sum(x) - sum(x-1)是否为0,为0的话则不存在,不为0的话,则add(x,-1)2:是查询比x大的数中第k大的数,先求出比x小的个数s,假设比x大的数中第k大的数为y,那么比y小的个数有s+k个二分y的值来找 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath&g

HDU 2852 KiKi&#39;s K-Number (树状数组 &amp;&amp; 二分)

题意:给出对容器的总操作次数n, 接下来是这n个操作.这里对于一个容器提供三种操作, 分别是插入.删除和查找.输入0  e表示插入e.输入1  e表示删除e,若元素不存在输出No Elment!.输入2  e  k表示查找比e大且第k大的数, 若不存在则输出Not Find! 分析:这里考虑树状数组做的原因是在第三个操作的时候, 只要我们记录了元素的总数, 那通过求和操作, 便能够高效地知道到底有多少个数比现在求和的这个数要大, 例如 tot - sum(3)就能知道整个集合里面比3大的数到底有

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 5592 ZYB&#39;s Premutation(树状数组+二分)

题意:给一个排列的每个前缀区间的逆序对数,让还原 原序列. 思路:考虑逆序对的意思,对于k = f[i] - f[i -1],就表示在第i个位置前面有k个比当前位置大的数,那么也就是:除了i后面的数字之外,它是在剩下的数字当中第k+1大的. 知道这个之后,可以用树状数组来帮助找出剩下的数中第k大的数,刚开始我们可以让1-n中每个元素都标记为1,那么他们的前缀和就代表它是第几小.所以,我们可以对于他们的和来二分快速寻找第k大数.其实在树状数组里面是按照第(i-k)小来找的.找完之后要删除这个元素的

TOJ 4602:高桥和低桥(二分或树状数组+二分)

描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上,所以不算"淹了两次".举例说明:假定高桥和低桥的高度分别是5和2,初始水位为1第一次洪水:水位提高到6(两个桥都被淹),退到2(高桥不再被淹,但低桥仍然被淹)第二次洪水:水位提高到8(高桥又被淹了),退到3.没错,文字游戏.关键在于"又"的含义.如果某次洪水退去之后一座桥仍然被淹(即水位不小于

ZOJ 3635 树状数组+二分

这题那时怎么想就是想不出来--而且今晚没有多大状态,自己都晕了--一题没做出来-- baoge解释好久才懂--唉--线段树,树状数组用得还是不够熟啊-- WA了二发,才知道二分错了,二分好久不用,老是出错了现在-- #include<iostream> #include<cstring> #include<string> #include<cstdio> #define sca(a) scanf("%d",&a) #define

POJ 2892 Tunnel Warfare (树状数组+二分)

题目大意: 三个操作 D pos  将pos位置摧毁,让它和周围不相连. Q pos 问和pos 相连的有多少个村庄. R 修复最近摧毁的村庄. 思路分析: 树状数组记录这个区间有多少个1. 如果  [s-e] 有e-s+1个1 的话.那么这个区间是相连的. 这样的话,我们就可以用二分的办法求出与某个位置最大相连的数量. 还有这里二分 while(l<=r) { if(满足) { ans=mid; l=mid+1; } else r=mid-1; } #include <cstdio>