[TJOI2010]中位数
(优先队列,堆)
题目概述:
给定长度为N的初始序列和M个操作,操作有两种:1.插入一个元素;2.查询当前序列的中位数。
数据规模:
N<=100000,M<=50000
思路:
这个题比较自然的思路就是先把初始队列排序后对半分开,然后用一个大根堆存1~N/2号元素,小根堆存N/2+1~N号元素,这样大根堆堆顶元素和小根堆堆顶元素就是当前的中位数的备选元素。然后执行插入操作的时候,与任意一个堆顶进行比较,以大根堆为例,如果小于大根堆堆顶,就把元素放入大根堆,反之进入小根堆。在每次查询之前,都要有一次调整,让大根堆的堆顶为中位数,如果大根堆规模大于(N+1)/2,就弹出堆顶至小根堆,反之,如果小根堆规模大于N-(N+1)/2,就弹出堆顶至大根堆,然后输出大根堆堆顶。
代码写的比较鬼畜,大家多担待。
代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
int i,j,m,n,temp,kg,a[100001];
priority_queue<int> q1;
priority_queue<int,vector<int>,greater<int> > q2;
int r()
{
int ans=0,f=1;
char ch;
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ans*=10;
ans+=ch-'0';
ch=getchar();
}
return ans*f;
}
int main()
{
n=r();
for(i=1;i<=n;i++)
a[i]=r();
sort(a+1,a+n+1);
for(i=1;i<=n/2;i++)
q1.push(a[i]);
for(i=n/2+1;i<=n;i++)
q2.push(a[i]);
string s;
int x,temp;
m=r();
for(i=1;i<=m;i++)
{
cin>>s;
if(s=="add")
{
x=r();
if(q1.top()<x)
q2.push(x);
else
q1.push(x);
n++;
}
else
{
while(q1.size()>n-n/2)
{
temp=q1.top();
q2.push(temp);
q1.pop();
}
while(q2.size()>n/2)
{
temp=q2.top();
q1.push(temp);
q2.pop();
}
printf("%d\n",q1.top());
}
}
return 0;
}