orz各位大佬,题解太强了,主席树,堆,线段树,splay,还有暴力,太巨了。所以我用的是fhq treap(好像更高级)。算了。
反正都是平衡树,这道题就是动态求中位数,不会做的同学可以先做弱化版P1168
至于不会fhq treap的同学可以先点这里或上 Patrickpwq大佬的博客
fhq treap做这道题涉及到insert(插入)与find(求第k小的数),至于k,就随add增大就好了,所以说fhq treap太好用了。
insert的原理就不说了,至于find的原理我就简单讲一下,fhq treap是用treap来存,treap就是堆与树的合并,所以我们叫它二叉搜索树,所以它具有堆的性质,所以就搜右子树大小。(详细可以戳上面)
嗯,上代码。
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 200010
using namespace std;
int n,val[maxn],rnd[maxn],son[maxn][3],size[maxn],sum_p,m;
//val存权值,rnd存rand出的值,son存左右儿子,size存大小。
inline void read(int &x)
{
x=0;int f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9')
{x=x*10+ch-'0';ch=getchar();}
x*=f;
}
inline int newnode(int x)
{
++sum_p;size[sum_p]=1;
val[sum_p]=x;rnd[sum_p]=rand();
return sum_p;
}
inline void update(int x)
{
size[x]=size[son[x][1]]+size[son[x][2]]+1;
}
inline void split(int &x,int &y,int k,int pos)//拆树
{
if(!pos)x=y=0;
else
{
if(val[pos]<=k)//(拆成比k大与不大于k)
{x=pos;split(son[pos][2],y,k,son[pos][2]);}
else
{y=pos;split(x,son[pos][1],k,son[pos][1]);}
update(pos);
}
}
inline int merge(int x,int y)//合并
{
if(x==0||y==0) return x+y;
if(rnd[x]<rnd[y])//如果rand[x]<rand[y] 我们就把y接在x的右儿子上
{
son[x][2]=merge(son[x][2],y);
update(x);return x;
}
else//反之同理
{
son[y][1]=merge(x,son[y][1]);
update(y);return y;
}
}
inline int find(int pos,int rank)
{
while(1)//(原理上面已讲)
{
if(size[son[pos][1]]>=rank)
{
pos=son[pos][1];
}
else
if(size[son[pos][1]]+1==rank)return pos;
else
{
rank-=size[son[pos][1]]+1;
pos=son[pos][2];
}
}
}
int main()
{
srand((unsigned)time(NULL));
int b,x,y,z,op,root=0,m;
read(n);
for(register int i=1;i<=n;i++)
{
read(op);
split(x,y,op,root);//拆开
root=merge(merge(x,newnode(op)),y);//插入,合并回来
}
read(m);char a[3];
for(register int i=1;i<=m;i++)
{
scanf("%s%d",a,&b);
if(a[0]=='a')
{
split(x,y,b,root);
root=merge(merge(x,newnode(b)),y);
n++;//中位数是动态的,所以改变总个数就好了。
}
else
{
register int mid=(n+1)/2;//加1的原因就不说了
printf("%d\n",val[find(root,mid)]);
}
}
}