Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-1e7,1e7]
数据如下http://pan.baidu.com/s/1jHMJwO2
正解:splay or treap or 替罪羊树
解题报告:
正解好多。
感觉写的比较好的题解:(传送门)
替罪羊树:https://zhuanlan.zhihu.com/p/21263304
treap:http://hzwer.com/1712.html
我也用几种算法都写了一遍。
替罪羊树:
感觉就是优化暴力,唯一比二叉搜索树更优秀的就是删除操作和重构操作,还是很神的。
代码如下:(我的常数取得是0.75,事实上可以再大一点)
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int MAXN = 200011; 21 const double A = 0.75; 22 int n,root,tot; 23 int ret;//判断是否需要重构 24 int son[MAXN][2],w[MAXN],del[MAXN],size[MAXN],zong[MAXN]; 25 //size记录当前未被删除的结点个数,zong记录结点个数 26 int q[MAXN],tail,father[MAXN]; 27 28 inline int getint() 29 { 30 int w=0,q=0; 31 char c=getchar(); 32 while((c<'0' || c>'9') && c!='-') c=getchar(); 33 if (c=='-') q=1, c=getchar(); 34 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 35 return q ? -w : w; 36 } 37 38 inline bool bad(int x){ 39 return (zong[son[x][0]]>zong[x]*A) || (zong[son[x][1]]>zong[x]*A); 40 } 41 42 inline void clear(int x,int zhi){ 43 son[x][0]=son[x][1]=0; 44 del[x]=0; size[x]=zong[x]=1; 45 w[x]=zhi; 46 } 47 48 inline void insert(int x,int o,int f){ 49 if(!o) { clear(n,x); father[n]=f; son[f][x>=w[f]]=n; return ; } 50 if(x>=w[o]) insert(x,son[o][1],o); 51 else insert(x,son[o][0],o); 52 size[o]++; zong[o]++; if(bad(o)) ret=o; 53 } 54 55 inline void update(int x){ 56 int l=son[x][0],r=son[x][1]; 57 size[x]=size[l]+size[r]+(del[x]^1); 58 zong[x]=zong[l]+zong[r]+1; 59 } 60 61 inline void build(int l,int r,int f,int fx){ 62 if(l>r) return ; 63 int mid=(l+r)/2; 64 son[q[mid]][0]=son[q[mid]][1]=father[q[mid]]=del[q[mid]]=0; 65 if(!f) root=q[mid]; else father[q[mid]]=f; 66 son[f][fx]=q[mid]; 67 if(l==r) {size[q[l]]=1;zong[q[l]]=1;son[q[l]][0]=son[q[l]][1]=0;return;}//!!! 68 build(l,mid-1,q[mid],0); build(mid+1,r,q[mid],1); 69 update(q[mid]); 70 } 71 72 inline void mid_dfs(int x){//中序遍历 73 if(son[x][0]) mid_dfs(son[x][0]); 74 if(!del[x]) q[++tail]=x; 75 if(son[x][1]) mid_dfs(son[x][1]); 76 } 77 78 inline void rebuild(int x){//替罪羊树的重构 79 tail=0; mid_dfs(x); 80 build(1,tail,father[x],(son[father[x]][1]==x)); 81 } 82 83 inline int rank(int x){//求x的排名 84 int t=root; int now=1; 85 while(t) { 86 if(x<=w[t]) t=son[t][0]; 87 else { 88 now+=(size[son[t][0]]+(del[t]^1)); 89 t=son[t][1]; 90 } 91 } 92 return now; 93 } 94 95 inline int kth(int x){//查找排名为x的数 96 int t=root; 97 while(t) { 98 if(x==size[son[t][0]]+1 && !del[t]) return w[t]; 99 if(size[son[t][0]]>=x) t=son[t][0]; 100 else { x-=size[son[t][0]]+(del[t]^1); t=son[t][1]; } 101 } 102 } 103 104 inline void out(int x,int o){//删除排名为x的一个点,删除的点打上标记即可 105 size[o]--; 106 int p=size[son[o][0]]+(del[o]^1); 107 if(p==x && !del[o]) { del[o]=1; return ; } 108 if(x<=p) out(x,son[o][0]); 109 else out(x-p,son[o][1]); 110 } 111 112 inline void work(){ 113 int T=getint(); int ljh,x; 114 while(T--) { 115 ljh=getint(); x=getint(); 116 if(ljh==1) { 117 n++; tot++; 118 if(tot==1) { root=1; clear(1,x); } 119 else { ret=0; insert(x,root,0); if(ret) rebuild(ret); } 120 } 121 else if(ljh==2) { tot--; out(rank(x+1)-1,root); if(size[root]<zong[root]*A) rebuild(root); }//已经删除的结点个数超过设定限制 122 else if(ljh==3) printf("%d\n",rank(x)); 123 else if(ljh==4) printf("%d\n",kth(x)); 124 else if(ljh==5) printf("%d\n",kth(rank(x)-1)); 125 else printf("%d\n",kth(rank(x+1))); 126 } 127 } 128 129 int main() 130 { 131 work(); 132 return 0; 133 }