#堆#JZOJ 2152 终极数

本文介绍了一种使用对顶堆(一个小根堆和一个大根堆)来求解序列前缀中位数的方法。通过对输入序列进行处理,动态维护两个堆的状态,最终找出整个序列的中位数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

给定一个长度为n的序列a,试求出对于序列a的每一个前缀的终极数x,使得
这里写图片描述
最小


分析

首先这道题比较搞事。
一开始还是一脸懵逼的
然后后来发现就是求1∼i(i≤n)1\sim i(i\leq n)1iin的中位数,这几个数的中位数
所以使用对顶堆


代码

#include <cstdio>
#include <algorithm>
using namespace std;
int a[500001],b[500001],c[1000001],n,x;
void up1(int x){while (x>1&&a[x]<a[x/2]) swap(a[x],a[x/2]),x/=2;}
void up2(int x){while (x>1&&b[x]>b[x/2]) swap(b[x],b[x/2]),x/=2;}
void down1(int x){ int y;
	while (x*2<=a[0]&&a[x]>a[x*2]||x*2+1<=a[0]&&a[x]>a[x*2+1]){
		if (x*2+1>a[0]||a[x*2]<a[x*2+1]) y=x*2; else y=x*2+1;
		swap(a[x],a[y]); x=y;}}
void down2(int x){ int y;
	while (x*2<=b[0]&&b[x]<b[x*2]||x*2+1<=b[0]&&b[x]<b[x*2+1]){
		if (x*2+1>b[0]||b[x*2]>b[x*2+1]) y=x*2; else y=x*2+1;
		swap(b[x],b[y]); x=y;}}
int main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		scanf("%d",&x);
		if (i%2) a[++a[0]]=x,up1(a[0]);//先插入小根堆
		else b[++b[0]]=x,up2(b[0]);//再插入大根堆
		while (a[1]<b[1]) swap(a[1],b[1]),down1(1),down2(1);//小根堆的堆顶比大根堆的堆顶大就交换,并维护两个堆
		c[i]=a[1];//中位数
	}
	sort(c+1,c+1+n); printf("%d",c[n/2]); return 0;//快排后正中间的输为中位数
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值