#链表 or 堆,对顶堆#poj 3784 Running Median

题目

动态求中位数


分析(离线)

这道题可以用链表做,倒着推,一个个从链表内删除,求中位数之前需要排序,当然需要标记每个数在链表出现的位置


链表代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define mod 10007
struct rec{
	int val,id;
	bool operator<(const rec &x)const{
		return val<x.val;
	}
}a[mod];
int t,n,f[mod],l[mod],r[mod],ans[mod];
int in(){
	int ans=0,f=1; char c=getchar();
	while ((c<48||c>57)&&c!='-') c=getchar();
	if (c=='-') f=-f,c=getchar();
	while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
	return ans*f;
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int main(){
	t=in();
	while (t--){
		int v=in(); n=in(); int k=n+1>>1; 
		print(v); putchar(' '); print(k); 
		putchar('\n'); int tv=0,mid=k;
		for (int i=1;i<=n;i++) a[i].val=in(),a[i].id=i;
		std::stable_sort(a+1,a+1+n); r[0]=1; l[n+1]=n;
		for (int i=1;i<=n;i++) f[a[i].id]=i,l[i]=i-1,r[i]=i+1;//快排&&建链表
		for (int i=n;;i-=2){
			if (i&1) ans[++tv]=a[mid].val;//中位数
			if (i==1) break;
			if (f[i]>=mid&&f[i-1]>=mid) mid=l[mid];//中位数在左边
			else if (f[i]<=mid&&f[i-1]<=mid) mid=r[mid];//中位数在右边
			l[r[f[i]]]=l[f[i]]; r[l[f[i]]]=r[f[i]]; 
			l[r[f[i-1]]]=l[f[i-1]]; r[l[f[i-1]]]=r[f[i-1]];//删除
		}
		for (int i=k;i>=1;i--){
			if (ans[i]<0) putchar('-'),ans[i]=-ans[i];
			if (ans[i]) print(ans[i]); 
			else putchar('0');
			if ((k-i)%10==9||i==1) putchar('\n'); else putchar(' '); 
		}
	}
	return 0;
}

#分析(在线)
也可以用对顶堆的方式,小根堆的堆顶就是中位数


#优先队列代码

#include <cstdio>
#include <queue>
std::priority_queue<int>q1,q2;
int in(){
	int ans=0,f=1; char c=getchar();
	while ((c<48||c>57)&&c!='-') c=getchar();
	if (c=='-') f=-f,c=getchar();
	while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
	return ans*f;
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int main(){
	int t=in();
	while (t--){
		int n=in(),tv=0; print(n); putchar(' ');
		n=in(); int k=n+1>>1; print(k); putchar('\n');
		while (q1.size()) q1.pop();//清空
		while (q2.size()) q2.pop();
		for (int i=1;i<=n;i++){
			int x=in();
			if (i&1) q1.push(-x); else q2.push(x);//q1取相反数可改成小根堆
			while (q1.size()&&q2.size()&&-q1.top()<q2.top()){//修改堆顶
				int x=-q1.top(); q1.pop();
				q1.push(-q2.top());
				q2.pop(); q2.push(x); 
			}
			if (i&1) {
			    if (q1.top()>0) putchar('-'),print(q1.top());
                else if (q1.top()<0) print(-q1.top()); 
                else putchar('0');
                if (i!=n&&i%20==19) putchar('\n'); else putchar(' ');
		    }
		}
		putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值