P3871 [TJOI2010]中位数(对顶堆)
题意
给定一个N个元素组成的整数序列,有两种操作:
1.add a 在该序列的最后添加一个整数a,新序列长度为n+1
2.mid 输出当前序列的中位数
输入格式
第一行为初始序列长度N。
第二行为N个整数,表示整数序列,数字之间用空格分隔。
第三行为操作数M,即要进行M次操作。
下面为M行,每行输入格式如题意所述。
输出格式
对于每个mid操作输出中位数的值
样例
input
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
output
5
13
思路
开两个优先队列,对顶堆。
从小到大排列的1~n/2的元素实时维护在第一个优先队列(从大到小)中,剩下的元素维护在第二个优先队列(从小到大)中。
当然也可以平衡树啦(Orz)
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
//#pragma GCC optimize(3)
#define pb push_back
#define is insert
#define PII pair<int,int>
#define show(x) cerr<<#x<<" : "<<x<<endl;
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}
const int INF=0x3f3f3f3f;//2147483647;
const int N=1e5+50,M=1e5+50;
const ll mod=998244353;
int n;
int a[N];
int m;
int mid;
priority_queue<int>ql;
priority_queue<int,vector<int>,greater<int>>qr;
void solve() {
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+1+n);
cin>>m;
int pos;
if(n&1){
mid=a[n/2+1];
pos=n/2+1;
}
else {
mid=min(a[n/2],a[n/2+1]);
if(a[n/2]<=a[n/2+1]){
pos=n/2;
}
else {
pos=n/2+1;
}
}
for(int i=1;i<=pos;i++){
ql.push(a[i]);
}
for(int j=pos+1;j<=n;j++){
qr.push(a[j]);
}
while(m--){
string s;cin>>s;
if(s[0]=='a'){
int tmp;cin>>tmp;
n++;
if(tmp>mid){
qr.push(tmp);
}
else {
ql.push(tmp);
}
if(n&1){
while(ql.size()>qr.size()){
int tmp=ql.top();
ql.pop();
qr.push(tmp);
}
while(ql.size()<qr.size()){
int tmp=qr.top();
qr.pop();
ql.push(tmp);
}
mid=ql.top();
}
else {
while(ql.size()>qr.size()){
int tmp=ql.top();
ql.pop();
qr.push(tmp);
}
while(ql.size()<qr.size()){
int tmp=qr.top();
qr.pop();
ql.push(tmp);
}
int q1=ql.top();int q2=qr.top();
if(q1<=q2){
mid=q1;
}
else {
mid=q2;
}
}
}
else {
cout<<mid<<"\n";
}
//cout<<"mid="<<mid<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int __=1;//cin>>__;
while(__--){
solve();
}
return 0;
}

浙公网安备 33010602011771号