博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ 3224: Tyvj 1728 普通平衡树 or 洛谷 P3369 【模板】普通平衡树-Splay树模板题
阅读量:4681 次
发布时间:2019-06-09

本文共 4337 字,大约阅读时间需要 14 分钟。

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 22483  Solved: 10130
[][][]

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.每个数的数据范围:[-2e9,2e9]
 
 
 
题目就是一个splay的模板,直接贴代码,代码里写了注释。
 
代码:
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 using namespace std; 20 typedef long long ll; 21 22 const double PI=acos(-1.0); 23 const double eps=1e-6; 24 const ll mod=1e9+7; 25 const int inf=0x3f3f3f3f; 26 const int maxn=1e6+10; 27 const int maxm=100+10; 28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 29 30 /* 31 平衡树的本质其实是二叉搜索树,所以很多操作是基于二叉搜索树的操作。 32 33 splay的本质是rotate,旋转其实只是为了保证二叉搜索树的平衡性。 34 35 所有的操作一定都满足二叉搜索树的性质,所有改变父子关系的操作一定要update 36 */ 37 38 int ch[maxn][2],f[maxn],size[maxn],cnt[maxn],key[maxn]; 39 /* 40 f[i]表示i的父节点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,key[i]表示i的关键字(即节点i代表的那个数) 41 cnt[i]表示i的关键字出现的次数(相当于权值),size[i]表示包括i在内的子树的大小 42 */ 43 int sz,root;//sz为整棵树的大小,root为整棵树的根 44 45 inline void clear(int x)//将当前点的各项清零(用于删除之后) 46 { 47 ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0; 48 } 49 50 inline bool get(int x)//判断当前点是它父节点的左儿子还是右儿子 51 { 52 return ch[f[x]][1]==x; 53 } 54 55 inline void update(int x)//更新当前点的size值(用于发生修改之后) 56 { 57 if(x){ 58 size[x]=cnt[x];//x的个数 59 if(ch[x][0]) size[x]+=size[ch[x][0]];//加上左右儿子的size 60 if(ch[x][1]) size[x]+=size[ch[x][1]]; 61 } 62 } 63 64 inline void rotate(int x)//伸展操作,旋转 65 { 66 int old=f[x],oldf=f[old],whichx=get(x);//找爸爸,爷爷,儿子 下面的以向右转为例子,反过来也一样的 67 ch[old][whichx]=ch[x][whichx^1];f[ch[old][whichx]]=old;//x的右儿子变为x的爸爸的左儿子,x的右儿子的爸爸变为x的爸爸 68 ch[x][whichx^1]=old;f[old]=x;//x的右儿子变为x以前的爸爸,x以前的爸爸的爸爸变为x 69 f[x]=oldf;//x的爸爸变为x以前的爷爷 70 if(oldf) 71 ch[oldf][ch[oldf][1]==old]=x;//以前x的爷爷的儿子是x以前的爸爸,现在更新为x 72 update(old);update(x);//更新 73 } 74 75 /* 76 splay的过程中需要分类讨论,如果是三点一线的情况(x,x的父亲,x的祖父) 需要先rotate x的父亲,否则需要先rotate本身,(否则会形成单旋使平衡树失衡) 77 */ 78 79 inline void splay(int x)//splay是rotate的发展,一直rotate到目标状态,如果有一个确定的目标状态,也可以传两个参数,一般是直接旋转到根 80 { 81 for(int fa;fa=f[x];rotate(x)) 82 if(f[fa]) 83 rotate(get(x)==get(fa)?fa:x); 84 root=x; 85 } 86 87 inline void insert(int x)//插入操作 88 { 89 if(root==0){ 90 sz++;ch[sz][0]=ch[sz][1]=f[sz]=0; 91 root=sz;size[sz]=cnt[sz]=1;key[sz]=x;return ; 92 } 93 int now=root,fa=0; 94 while(1){ 95 if(x==key[now]){ //如果这个数在树中已经出现了 96 cnt[now]++;update(now);update(fa);splay(now);break; 97 } 98 fa=now;now=ch[now][key[now]
1){cnt[root]--;update(root);return ;}//现在x为根,如果满足cnt[root]>1,即不只有一个x的话,直接-1160 if(!ch[root][0]&&!ch[root][1]) {clear(root);root=0;return ;}//如果root没有孩子,说明树上只有一个x,直接clear161 if(!ch[root][0]){ //如果root只有左儿子或者只有右儿子,直接clear root,然后把唯一的儿子当成根,(f变为0,root变为唯一的儿子)162 int oldroot=root;root=ch[root][1];;f[root]=0;clear(oldroot);return ;163 }164 else if(!ch[root][1]){165 int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return ;166 }167 //其他的就是有两个儿子的情况 如果有两个儿子的话,首先我们要先选一个根,自然是x的前驱或后继,这里我们选择前驱,然后把前驱旋转到根节点,然后再把x原来的右子树当做它的右子树,update维护一下就行。168 int leftbig=pre(),oldroot=root;//找到新根,也就是x的前驱,将其旋转到根,然后将原来的x的右儿子接到新根的右子树上(此操作需要改变父子关系)实际上就是把x删除,不要忘记update新根169 splay(leftbig);170 ch[root][1]=ch[oldroot][1];171 f[ch[oldroot][1]]=root;172 clear(oldroot);173 update(root);174 }175 176 int main()177 {178 int n,opt,x;179 scanf("%d",&n);180 for(int i=1;i<=n;i++){181 scanf("%d%d",&opt,&x);182 switch(opt){183 case 1: insert(x); break;//插入x数184 case 2: del(x); break;//删除x数(若有多个相同的数,因只删除一个)185 case 3: printf("%d\n",find(x)); break;//查询x数的排名(若有多个相同的数,因输出最小的排名)186 case 4: printf("%d\n",findx(x)); break;//查询排名为x的数187 case 5: insert(x); printf("%d\n",key[pre()]); del(x); break;// 求x的前驱(前驱定义为小于x,且最大的数)188 case 6: insert(x);printf("%d\n",key[next()]); del(x); break;//求x的后继(后继定义为大于x,且最小的数)189 }190 }191 }

 

 

 

 

先这样。。。

 

 

转载于:https://www.cnblogs.com/ZERO-/p/9606696.html

你可能感兴趣的文章
how to control project
查看>>
转 python新手容易犯的6个错误
查看>>
第四节 -- 列表
查看>>
决策树
查看>>
团队作业
查看>>
如何避免在简单业务逻辑上面的细节上面出错
查看>>
大型网站高并发的架构演变图-摘自网络
查看>>
8丶运行及总结
查看>>
WPF中使用USERCONTROL
查看>>
图片,base64 互转
查看>>
cache—主存—辅存三级调度模拟
查看>>
Java线程的定义
查看>>
Python-面向对象(组合、封装与多态)
查看>>
Mininet
查看>>
COSC2531 Programming Fundamentals
查看>>
设计模式系列 - 访问者模式
查看>>
20180507小测
查看>>
eclipse左侧不见
查看>>
python会缓存小的整数和短小的字符
查看>>
格网与四叉树索引
查看>>