P3871 [TJOI2010]中位数
作者:互联网
简要题意
你需要维护一个初始长度为 \(N\) 的序列 \(A\),有 \(M\) 个操作,支持:
add a
在 \(A\) 末尾插入一个数 \(a\)。mid
求 \(A\) 的中位数中位数是指将一个序列按照从小到大排序后处在中间位置的数。(若序列长度为偶数,则指处在中间位置的两个数中较小的那个)
\(1 \le N \le 10^5,0 \le M \le 10^4\),保证任意时刻 \(|A_i|,|a| \le 10^{9}\)。
思路
不难发现,如果 \(A\) 是有序的,长度为 \(N\) 的序列,那么 \(A\) 的中位数 \(A_m\) 满足:
\[m={\lfloor \frac{N+1}{2} \rfloor} \]维护有序的序列,当然选用平衡树啦。这里用的是 \(\text{FHQ - Treap}\)。
代码
#define int long long
using namespace std;
namespace FHQTreap{
const int SIZE = 2e5+5;
int son[SIZE][2];
int val[SIZE],rk[SIZE],siz[SIZE],root,points;
mt19937 randomer(time(0));
#define ls(i) (son[(i)][0])
#define rs(i) (son[(i)][1])
void pushup(int i){
siz[i]=siz[ls(i)]+siz[rs(i)]+1;
}
int newnode(int v){
val[++points]=v;
rk[points]=randomer();
siz[points]=1;
return points;
}
void split(int p,int v,int &left,int &right){
if(!p){
left=right=0;
return;
}
if(val[p]<=v){
left=p;
split(rs(p),v,rs(left),right);
}
else{
right=p;
split(ls(p),v,left,ls(right));
}
pushup(p);
}
int merge(int left,int right){
if(!left||!right){
if(left)return left;
else if(right)return right;
else return 0;
}
if(rk[left]<rk[right]){
ls(right)=merge(left,ls(right));
pushup(right);
return right;
}
else{
rs(left)=merge(rs(left),right);
pushup(left);
return left;
}
}
void insert(int v){
int left=0,right=0;
split(root,v-1,left,right);
root=merge(merge(left,newnode(v)),right);
}
int kth(int k){
int now=root;
while(1){
if(k<=siz[ls(now)]){
now=ls(now);
}
else if(k==siz[ls(now)]+1){
return val[now];
}
else{
k-=siz[ls(now)]+1;
now=rs(now);
}
}
}
}
namespace solution{
int n,m;
int solution(){
cin>>n;
for(int i=1,v;i<=n;i++){
cin>>v;
FHQTreap::insert(v);
}
cin>>m;
while(m--){
string op;
int m;
cin>>op;
if(op=="add"){
cin>>m;
FHQTreap::insert(m);
n++;
}
else{
cout<<FHQTreap::kth((n+1)/2)<<'\n';
}
}
return 0;
}
}
signed main(){
return solution::solution();
}
标签:le,int,siz,points,中位数,TJOI2010,P3871,SIZE 来源: https://www.cnblogs.com/zheyuanxie/p/p3871.html