题目大意:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
6. 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)。
解题思路:
可持久化平衡树,用非旋Treap实现。
和普通Treap其实没什么区别,主要是split和平常写的重量平衡树有点不同,然后每次要新建节点,其他都一样。
C++ Code:
#include<bits/stdc++.h> #define N 500005 struct node{ int r,ls,rs,s,sz; }a[N*50]; int rt[N],cnt=0; inline int readint(){ int c=getchar(),d=0,b=0; for(;!isdigit(c);c=getchar())b=c=='-'; for(;isdigit(c);c=getchar())d=(d<<3)+(d<<1)+(c^'0'); return b?-d:d; } inline void update(int x){ a[x].sz=a[a[x].ls].sz+a[a[x].rs].sz+1; } void split(int u,int k,int& x,int& y){ if(!u)x=y=0; else{ if(a[u].s<=k){ a[x=++cnt]=a[u]; split(a[x].rs,k,a[x].rs,y); update(x); }else{ a[y=++cnt]=a[u]; split(a[y].ls,k,x,a[y].ls); update(y); } } } int merge(int x,int y){ if(!x||!y)return x|y; int u; if(a[x].r<a[y].r){ a[u=++cnt]=a[x]; a[u].rs=merge(a[u].rs,y); }else{ a[u=++cnt]=a[y]; a[u].ls=merge(x,a[u].ls); } update(u); return u; } void Insert(int& root,int w){ int x,y,z; split(root,w,x,y); a[z=++cnt]=(node){rand(),0,0,w,1}; root=merge(merge(x,z),y); } void Delete(int& root,int w){ int x,y,z; split(root,w,x,y); split(x,w-1,x,z); if(a[z].s==w) root=merge(merge(x,merge(a[z].ls,a[z].rs)),y);else root=merge(merge(x,z),y); } int getpos(int now,int k){ for(;;){ if(k<=a[a[now].ls].sz)now=a[now].ls; if(k==a[a[now].ls].sz+1)return now; if(k>a[a[now].ls].sz)k-=a[a[now].ls].sz+1,now=a[now].rs; } } int kth(int rt,int w){ int x,y,rank; split(rt,w-1,x,y); rank=a[x].sz+1; rt=merge(x,y); return rank; } int find(int rt,int w){ return a[getpos(rt,w)].s; } int pre(int rt,int w){ int x,y,ans; split(rt,w-1,x,y); if(!x)ans=-2147483647;else ans=a[x].sz; if(ans!=-2147483647) ans=find(x,ans); rt=merge(x,y); return ans; } int nxt(int rt,int w){ int x,y,ans; split(rt,w,x,y); if(!y)ans=2147483647;else ans=a[y].sz; if(ans!=2147483647) ans=find(y,1); rt=merge(x,y); return ans; } int main(){ srand(20170607); memset(rt,0,sizeof rt); memset(a,0,sizeof a); for(int T=readint(),now=1;now<=T;++now){ int v=readint(),opt=readint(),x=readint(); rt[now]=rt[v]; if(opt==1)Insert(rt[now],x);else if(opt==2)Delete(rt[now],x);else if(opt==3)printf("%d ",kth(rt[now],x));else if(opt==4)printf("%d ",find(rt[now],x));else if(opt==5)printf("%d ",pre(rt[now],x));else printf("%d ",nxt(rt[now],x)); } return 0; }