题解 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 }