Evanyou Blog 彩带

洛谷P1168中位数

传送门啦

基本思想就是二分寻找答案,然后用树状数组去维护有几个比这个二分出来的值大,然后就没有了;
数据要离散,这个好像用map也可以,但是不会;

那怎么离散呢?
我们先把a数组读入并复制给s数组,然后排序a;
这个时候a数组就有序了,我们就可以把s数组里的值通过二分找到其在a数组里的下标,这样就把1~1e9的数据压缩到1e5了;

这样的离散支持去重,支持不去重;

离散后我们应该怎么办呢??

我们能用树状数组来维护前缀和;
那我们每增加一个数,我们就把他当作下标,在上面+1;然后我统计小于等于x的个数时直接取x的前缀和好了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100005;

inline int read(){
	char ch = getchar();
	int f = 1 ,x = 0;
	while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();}
	while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
	return x * f;
}

int n,a[maxn],tot;
int bit[maxn],s[maxn];

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

inline void add(int x,int y){
	for(x; x <= tot; x += lowbit(x))
		bit[x] += y;
}

inline int query(int k){
	int ans = 0 , now = 0;
	for(int i=20;i>=0;i--){
		ans += (1 << i);//先让答案加上 
		if(ans > tot || now + bit[ans] >= k)
	//如果超了总体的最大值(防止数组越界),或者是 超过了k个,就退回去,这里注意是大于等于,因为要考虑有重复元素,所以我们找的其实是一个满足小于他的个数小于k的最大数
			ans -= (1 << i);
		else now += bit[ans];
	}
	return ans + 1;
}

int main(){
	n = read();
	for(int i=1;i<=n;i++){
		a[++tot] = read();
		s[i] = a[i];
	}
	sort(a + 1 , a + 1 + n);
	tot = unique(a + 1 , a + 1 + tot) - a - 1;
	for(int i=1;i<=n;i++)
		s[i] = lower_bound(a + 1 , a + 1 + tot , s[i]) - a;
	for(int i=1;i<=n;i++){
		add(s[i] , 1);
		if(i & 1)//题目要求 
			printf("%d\n",a[query((i + 1) >> 1)] );
	}
	return 0;
}
posted @ 2018-11-02 15:53  Stephen_F  阅读(126)  评论(0编辑  收藏  举报