P1168 中位数

P1168 中位数

传送门

思路:

1.对顶堆,大根堆(从大到小)存较小的数,小根堆(从小到大)存较大的数。

如果当前数大于大根堆顶,就放入小根堆,否则放入大根堆。

然后维护使两堆容量大小之差小于等于1,然后容量较大的那个堆顶元素即是答案。

因为题目保证是求奇数个数的中位数,显然比中位数小的个数=比中位数大的个数,所以取多了那一个的堆顶即可。

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
priority_queue<int>q1;	//大根堆 
priority_queue<int,vector<int>,greater<int> >q2;//小根堆 
int main(){
	int  n,x; 
	scanf("%d%d",&n,&x);q1.push(x);
	printf("%d\n",x);
	for(int i=2;i<=n;i++){
		scanf("%d",&x);
		if(x>q1.top()) q2.push(x);
		else q1.push(x);
		while(abs((int)q1.size()-(int)q2.size())>1){
			if(q1.size()>q2.size()) q2.push(q1.top()),q1.pop();
			else q1.push(q2.top()),q2.pop();
		}
		if(i&1){
			if(q1.size()>q2.size()) printf("%d\n",q1.top());
			else printf("%d\n",q2.top());
		}
	}
	return 0;
}

2.权值树状数组离散化+二分。

找中位数即是找第 k + 1 2 \dfrac{k+1}{2} 2k+1小的数。

显然我们可以二分枚举权值的大小是多少,即最大值最小化,大于等于 k + 1 2 \dfrac{k+1}{2} 2k+1的权值最小化即使权值答案,然后输出权值对于的元素即可。

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
#define lowbit(x) x&(-x)
int n,tr[N],cnt,a[N],b[N];
void add(int x,int v){
	while(x<=cnt) tr[x]+=v,x+=lowbit(x);
}
int sum(int x){
	int ans=0;
	while(x){
		ans+=tr[x];
		x-=lowbit(x);
	}
	return ans;
} 
int Find(int x){
	int l=1,r=cnt;
	while(l<=r){
		int mid=(l+r)>>1; 
		if(sum(mid)>=x) r=mid-1;
		else l=mid+1;
	}
	return b[l];
}
int main(){	
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+n+1);
	cnt=unique(b+1,b+n+1)-(b+1);
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
	for(int i=1;i<=n;i++){
		add(a[i],1);
		if(i&1) printf("%d\n",Find((i+1)/2));
	}
	return 0;
}

3.对于第二种方式还可以用倍增法找权值,倒序枚举权值的位,找到小于 a n s ans ans的最大 i d id id,答案就是 b [ i d + 1 ] b[id+1] b[id+1]

#include
using namespace std;
typedef long long ll;
const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair
#define fi first 
#define se second
#define lowbit(x) x&(-x)
int n,tr[N],cnt,a[N],b[N];
void add(int x,int v){
	while(x<=cnt) tr[x]+=v,x+=lowbit(x);
}

int fun(int k){
	int id=0,sum=0;
	for(int i=20;i>=0;i--){
		id+=(1<<i);
		if(id>cnt||sum+tr[id]>=k) id-=(1<<i);
		else sum+=tr[id];
	}
	return b[id+1];
}
int main(){	
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+n+1);
	cnt=unique(b+1,b+n+1)-(b+1);
	for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
	for(int i=1;i<=n;i++){
		add(a[i],1);
		if(i&1) printf("%d\n",fun((i+1)/2));
	}
	return 0;
}

你可能感兴趣的:(堆,离散化,树状数组,树状数组,堆,二分)