给定一个由 N N N 个元素组成的整数序列,现在有两种操作:
中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)
例 1 1 1: [ 1 , 2 , 13 , 14 , 15 , 16 ] [1, 2, 13, 14, 15, 16] [1,2,13,14,15,16] 中位数为 13 13 13。
例 2 2 2: [ 1 , 3 , 5 , 7 , 10 , 11 , 17 ] [1, 3, 5, 7, 10, 11, 17] [1,3,5,7,10,11,17] 中位数为 7 7 7。
例 3 3 3: [ 1 , 1 , 1 , 2 , 3 ] [1, 1, 1, 2, 3] [1,1,1,2,3] 中位数为 1 1 1。
第一行为初始序列长度 N N N。第二行为 N N N 个整数,表示整数序列,数字之间用空格分隔。第三行为操作数 M M M,即要进行 M M M 次操作。下面为 M M M 行,每行输入格式如题意所述。
对于每个 mid \verb!mid! mid 操作输出中位数的值。
6
1 2 13 14 15 16
5
add 5
add 3
mid
add 20
mid
5
13
序列中整数的绝对值不超过 1 0 9 10^9 109,序列中的数可能有重复。
由于我们要求中位数,若当前序列的长度 n n n为奇数,则我们需要求排序后位于第 n / 2 + 1 n/2+1 n/2+1。若为奇数,则求 m i n ( n / 2 , n / 2 + 1 ) min(n/2,n/2+1) min(n/2,n/2+1)。不管求第几个,我们都要实现如下操作:
我们直接平衡树启动。每次记录一下序列长度。
#include
using namespace std;
#define ll long long
struct lit{
ll val,pri,siz;
lit *l,*r;
lit(ll v){
val=v;pri=rand();siz=1;
l=r=nullptr;
}
};
class FHQ_Treap{//FHQ无旋平衡树
private:
lit *root;
ll getsize(lit *u){return u?u->siz:0;}//安全访问size
void pushup(lit *&u){//更新当前节点的siz值
if(!u)return ;
u->siz=1+getsize(u->l)+getsize(u->r);
}
void split(lit *u,ll v,lit *&x,lit *&y){//分裂
if(!u){x=y=nullptr;return;}
if(u->val<=v){x=u;split(u->r,v,x->r,y);pushup(x);}
else{y=u;split(u->l,v,x,y->l);pushup(y);}
}
lit *merge(lit *x,lit *y){//合并
if(!x)return y;
if(!y)return x;
if(x->pri>y->pri){x->r=merge(x->r,y);pushup(x);return x;}
else {y->l=merge(x,y->l);pushup(y);return y;}
}
lit *getkth(lit *u,ll k){//求第k个元素
if(!u)return nullptr;
ll ls=getsize(u->l);
if(ls+1<k)return getkth(u->r,k-ls-1);
else if(k<ls+1)return getkth(u->l,k);
return u;
}
public:
void insert(ll v){//加入一个节点
lit *l,*r;
split(root,v,l,r);
root=merge(merge(l,new lit(v)),r);
}
ll kth(ll k){//封装
lit *p=getkth(root,k);
return p->val;
}
}tr;
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll n;int len=0;
cin>>len;
for(int i=1;i<=len;i++){
int x;cin>>x;tr.insert(x);
}
cin>>n;
for(ll i=1;i<=n;i++){
string op;int x;
cin>>op;
if(op=="add"){
cin>>x;tr.insert(x);len++;
}
else{
int ans;
if(len%2==0){//为偶数
ans=min(tr.kth(len/2),tr.kth(len/2+1));
}//为奇数
else ans=tr.kth(len/2+1);
cout<<ans<<'\n';
}
}
return 0;
}