题解 P3871 【[TJOI2010]中位数】

orz各位大佬,题解太强了,主席树,堆,线段树,splay,还有暴力,太巨了。所以我用的是fhq treap(好像更高级)。算了。

反正都是平衡树,这道题就是动态求中位数,不会做的同学可以先做弱化版P1168

至于不会fhq treap的同学可以先点这里或上 Patrickpwq大佬的博客

fhq treap做这道题涉及到insert(插入)与find(求第k小的数),至于k,就随add增大就好了,所以说fhq treap太好用了。

insert的原理就不说了,至于find的原理我就简单讲一下,fhq treap是用treap来存,treap就是堆与树的合并,所以我们叫它二叉搜索树,所以它具有堆的性质,所以就搜右子树大小。(详细可以戳上面)

嗯,上代码。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<ctime>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #define maxn 200010
  8 using namespace std;
  9 int n,val[maxn],rnd[maxn],son[maxn][3],size[maxn],sum_p,m;
 10 //val存权值,rnd存rand出的值,son存左右儿子,size存大小。
 11 inline void read(int &x)
 12 {
 13     x=0;int f=1; 
 14     char ch=getchar();
 15     while(ch<'0'||ch>'9')
 16     {if(ch=='-') f=-1; ch=getchar();}
 17     while(ch>='0'&&ch<='9')
 18     {x=x*10+ch-'0';ch=getchar();}
 19     x*=f;
 20 }
 21 inline int newnode(int x)
 22 {
 23     ++sum_p;size[sum_p]=1;
 24     val[sum_p]=x;rnd[sum_p]=rand();
 25     return sum_p; 
 26 }
 27 inline void update(int x)
 28 {
 29     size[x]=size[son[x][1]]+size[son[x][2]]+1;
 30 }
 31 inline void split(int &x,int &y,int k,int pos)//拆树
 32 {
 33     if(!pos)x=y=0;
 34     else
 35     {
 36         if(val[pos]<=k)//(拆成比k大与不大于k)
 37         {x=pos;split(son[pos][2],y,k,son[pos][2]);}
 38         else
 39         {y=pos;split(x,son[pos][1],k,son[pos][1]);}
 40         update(pos);
 41     }
 42 }
 43 inline int merge(int x,int y)//合并
 44 {
 45     if(x==0||y==0) return x+y;
 46     if(rnd[x]<rnd[y])//如果rand[x]<rand[y] 我们就把y接在x的右儿子上
 47     {
 48         son[x][2]=merge(son[x][2],y);
 49         update(x);return x;
 50     }
 51     else//反之同理
 52     {
 53         son[y][1]=merge(x,son[y][1]);
 54         update(y);return y;
 55     }
 56 }
 57 inline int find(int pos,int rank)
 58 {
 59     while(1)//(原理上面已讲)
 60     {
 61         if(size[son[pos][1]]>=rank)
 62         {
 63             pos=son[pos][1];
 64         }
 65         else 
 66         if(size[son[pos][1]]+1==rank)return pos;
 67         else
 68         {
 69             rank-=size[son[pos][1]]+1;
 70             pos=son[pos][2];
 71         }
 72     }
 73 }
 74 int main()
 75 {
 76     srand((unsigned)time(NULL));
 77     int b,x,y,z,op,root=0,m;
 78     read(n);
 79     for(register int i=1;i<=n;i++)
 80     {
 81         read(op);
 82         split(x,y,op,root);//拆开
 83         root=merge(merge(x,newnode(op)),y);//插入,合并回来
 84     }
 85     read(m);char a[3]; 
 86     for(register int i=1;i<=m;i++)
 87     {
 88         scanf("%s%d",a,&b);
 89         if(a[0]=='a')
 90         {
 91             split(x,y,b,root);
 92             root=merge(merge(x,newnode(b)),y);
 93             n++;//中位数是动态的,所以改变总个数就好了。
 94         }
 95         else
 96         {
 97             register int mid=(n+1)/2;//加1的原因就不说了
 98             printf("%d\n",val[find(root,mid)]);
 99         }
100     }
101 }

 

posted @ 2018-08-23 21:22  __mashiro  阅读(192)  评论(0编辑  收藏  举报