BZOJ3224 Tyvj 1728 普通平衡树

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

Sample Output

106465
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 }

 

转载于:https://www.cnblogs.com/ljh2000-jump/p/5692136.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值