3224: Tyvj 1728 普通平衡树

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

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的模板,直接贴代码,代码里写了注释。
 
代码:
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#include<cassert>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<deque>
#include<iomanip>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll; const double PI=acos(-1.0);
const double eps=1e-;
const ll mod=1e9+;
const int inf=0x3f3f3f3f;
const int maxn=1e6+;
const int maxm=+;
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); /*
平衡树的本质其实是二叉搜索树,所以很多操作是基于二叉搜索树的操作。 splay的本质是rotate,旋转其实只是为了保证二叉搜索树的平衡性。 所有的操作一定都满足二叉搜索树的性质,所有改变父子关系的操作一定要update
*/ int ch[maxn][],f[maxn],size[maxn],cnt[maxn],key[maxn];
/*
f[i]表示i的父节点,ch[i][0]表示i的左儿子,ch[i][1]表示i的右儿子,key[i]表示i的关键字(即节点i代表的那个数)
cnt[i]表示i的关键字出现的次数(相当于权值),size[i]表示包括i在内的子树的大小
*/
int sz,root;//sz为整棵树的大小,root为整棵树的根 inline void clear(int x)//将当前点的各项清零(用于删除之后)
{
ch[x][]=ch[x][]=f[x]=size[x]=cnt[x]=key[x]=;
} inline bool get(int x)//判断当前点是它父节点的左儿子还是右儿子
{
return ch[f[x]][]==x;
} inline void update(int x)//更新当前点的size值(用于发生修改之后)
{
if(x){
size[x]=cnt[x];//x的个数
if(ch[x][]) size[x]+=size[ch[x][]];//加上左右儿子的size
if(ch[x][]) size[x]+=size[ch[x][]];
}
} inline void rotate(int x)//伸展操作,旋转
{
int old=f[x],oldf=f[old],whichx=get(x);//找爸爸,爷爷,儿子 下面的以向右转为例子,反过来也一样的
ch[old][whichx]=ch[x][whichx^];f[ch[old][whichx]]=old;//x的右儿子变为x的爸爸的左儿子,x的右儿子的爸爸变为x的爸爸
ch[x][whichx^]=old;f[old]=x;//x的右儿子变为x以前的爸爸,x以前的爸爸的爸爸变为x
f[x]=oldf;//x的爸爸变为x以前的爷爷
if(oldf)
ch[oldf][ch[oldf][]==old]=x;//以前x的爷爷的儿子是x以前的爸爸,现在更新为x
update(old);update(x);//更新
} /*
splay的过程中需要分类讨论,如果是三点一线的情况(x,x的父亲,x的祖父) 需要先rotate x的父亲,否则需要先rotate本身,(否则会形成单旋使平衡树失衡)
*/ inline void splay(int x)//splay是rotate的发展,一直rotate到目标状态,如果有一个确定的目标状态,也可以传两个参数,一般是直接旋转到根
{
for(int fa;fa=f[x];rotate(x))
if(f[fa])
rotate(get(x)==get(fa)?fa:x);
root=x;
} inline void insert(int x)//插入操作
{
if(root==){
sz++;ch[sz][]=ch[sz][]=f[sz]=;
root=sz;size[sz]=cnt[sz]=;key[sz]=x;return ;
}
int now=root,fa=;
while(){
if(x==key[now]){//如果这个数在树中已经出现了
cnt[now]++;update(now);update(fa);splay(now);break;
}
fa=now;now=ch[now][key[now]<x];
if(now==){//如果到了最底下,还是没找到,说明要插入新的值,整棵树的大小+1,新节点的左儿子右儿子(虽然为空)父节点等各个值都一一对应,然后做一下他父亲的update(做自己的没必要),做一下splay
sz++;ch[sz][]=ch[sz][]=;
f[sz]=fa;size[sz]=cnt[sz]=;
ch[fa][key[fa]<x]=sz;key[sz]=x;
update(fa);splay(sz);break;
}
}
} inline int find(int x)//查找x的排名
{
int now=root,ans=;
while(){
if(x<key[now]) now=ch[now][];//x比当前的小,继续找左子树
else{
ans+=(ch[now][]?size[ch[now][]]:);
if(x==key[now]){
splay(now);return ans+;
}
ans+=cnt[now];
now=ch[now][];
}
}
} inline int findx(int x)//找到排名为x的点
{
int now=root;
while(){
if(ch[now][]&&x<=size[ch[now][]])
now=ch[now][];
else{
int temp=(ch[now][]?size[ch[now][]]:)+cnt[now];
if(x<=temp) return key[now];
x-=temp;now=ch[now][];
}
}
} /*
因为在做insert操作之后做了一遍splay,这就意味着我们把x已经splay到根了,所以pre/next操作就很好实现了
*/ inline int pre()//求x的前驱(其实就是求x的左子树的最右边的一个节点)
{
int now=ch[root][];
while(ch[now][]) now=ch[now][];
return now;
} inline int next()//求x的后继(其实就是求x的右子树的左边的一个节点)
{
int now=ch[root][];
while(ch[now][]) now=ch[now][];
return now;
} inline void del(int x)//删除操作
{
int whatever=find(x);//find一下,目的是将x旋转到根
if(cnt[root]>){cnt[root]--;update(root);return ;}//现在x为根,如果满足cnt[root]>1,即不只有一个x的话,直接-1
if(!ch[root][]&&!ch[root][]) {clear(root);root=;return ;}//如果root没有孩子,说明树上只有一个x,直接clear
if(!ch[root][]){//如果root只有左儿子或者只有右儿子,直接clear root,然后把唯一的儿子当成根,(f变为0,root变为唯一的儿子)
int oldroot=root;root=ch[root][];;f[root]=;clear(oldroot);return ;
}
else if(!ch[root][]){
int oldroot=root;root=ch[root][];f[root]=;clear(oldroot);return ;
}
//其他的就是有两个儿子的情况 如果有两个儿子的话,首先我们要先选一个根,自然是x的前驱或后继,这里我们选择前驱,然后把前驱旋转到根节点,然后再把x原来的右子树当做它的右子树,update维护一下就行。
int leftbig=pre(),oldroot=root;//找到新根,也就是x的前驱,将其旋转到根,然后将原来的x的右儿子接到新根的右子树上(此操作需要改变父子关系)实际上就是把x删除,不要忘记update新根
splay(leftbig);
ch[root][]=ch[oldroot][];
f[ch[oldroot][]]=root;
clear(oldroot);
update(root);
} int main()
{
int n,opt,x;
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d%d",&opt,&x);
switch(opt){
case : insert(x); break;//插入x数
case : del(x); break;//删除x数(若有多个相同的数,因只删除一个)
case : printf("%d\n",find(x)); break;//查询x数的排名(若有多个相同的数,因输出最小的排名)
case : printf("%d\n",findx(x)); break;//查询排名为x的数
case : insert(x); printf("%d\n",key[pre()]); del(x); break;// 求x的前驱(前驱定义为小于x,且最大的数)
case : insert(x);printf("%d\n",key[next()]); del(x); break;//求x的后继(后继定义为大于x,且最小的数)
}
}
}

先这样。。。

 

BZOJ 3224: Tyvj 1728 普通平衡树 or 洛谷 P3369 【模板】普通平衡树-Splay树模板题的更多相关文章

  1. BZOJ 3224: Tyvj 1728 普通平衡树

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 9629  Solved: 4091[Submit][Sta ...

  2. BZOJ 3224 TYVJ 1728 普通平衡树 [Treap树模板]

    3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 7390  Solved: 3122 [Submit][S ...

  3. BZOJ 3224: Tyvj 1728 普通平衡树 treap

    3224: Tyvj 1728 普通平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除 ...

  4. BZOJ 3224: Tyvj 1728 普通平衡树 vector

    3224: Tyvj 1728 普通平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除 ...

  5. BZOJ 3224: Tyvj 1728 普通平衡树(BST)

    treap,算是模板题了...我中间还一次交错题... -------------------------------------------------------------------- #in ...

  6. bzoj 3224: Tyvj 1728 普通平衡树 && loj 104 普通平衡树 (splay树)

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 思路: splay树模板题: 推荐博客:https://blog.csdn.ne ...

  7. BZOJ 3224 Tyvj 1728 普通平衡树模板

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3224 题目大意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以 ...

  8. bzoj 3224/Tyvj 1728 普通平衡树(splay)

    Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数 ...

  9. fhq_treap || BZOJ 3224: Tyvj 1728 普通平衡树 || Luogu P3369 【模板】普通平衡树

    题面:[模板]普通平衡树 代码: #include<cstdio> #include<cstring> #include<iostream> #include< ...

随机推荐

  1. Struts2拦截指定方法的拦截器

    作者:禅楼望月 默认情况下,我们为一个Action配置一个拦截器,该拦截器会拦截该Action中的所有方法,但是有时候我们只想拦截指定的方法.为此,需要使用struts2拦截器的方法过滤特性. 要使用 ...

  2. 数据结构—队列(Queue)

    队列的定义--Queue 队列是只允许在表的队尾插入,在表的队头进行删除.队列具有先进先出的特性(FIFO, First In First Out). 队列提供了下面的操作 q.empty() 如果队 ...

  3. [CF735D]Taxes

    题目大意:给你$n$,把它分成若干个数$n_i$,记价值为$\sum_{i=1}^k(\sum_{j|n_i}j-n_i)$(即分成的每个数的约数和(不包括自身)).(以前写的题,不知道为什么没交) ...

  4. CMU Bomblab 答案

    室友拉我做的... http://csapp.cs.cmu.edu/3e/labs.html Border relations with Canada have never been better. ...

  5. Spring学习--实现 FactoryBean 接口在 Spring IOC 容器中配置 Bean

    Spring 中有两种类型的 bean , 一种是普通的 bean , 另一种是工厂 bean , 即 FactroyBean. 工厂 bean 跟普通 bean 不同 , 其返回的对象不是指定类的一 ...

  6. css3 新旧伸缩盒的异同

    由于不需要理会IE浏览器,伸缩盒(flexible box)移动端开发中非常好用! 工作中使用APICLOUD开发手机App,老板要求兼容到安卓2.3(新版的需要安卓4.4以上),所以一直使用的是旧版 ...

  7. 我自己的python开发环境

    1.开发工具 eclipse 所有的版本下载: https://www.eclipse.org/downloads/index-packages.php , 我下载的是比较低的版本:https://w ...

  8. Eclipse Jetty调试时无法保存js文件

    Jetty会使用内存映射文件来缓存静态文件,包括js,css文件. 在Windows下,使用内存映射文件会导致文件被锁定,所以当Jetty启动的时候无法在编辑器对js或者css文件进行编辑. 解决办法 ...

  9. bzoj 1601 最小生成树

    原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1601 最小生成树的比较水的题,我们只需要加一个源点,连向所有的点,边权为每个点建水库的代价 ...

  10. 会话Cookie

    Cookie分为会话Cookie和本地Cookie两种 之前一直理解的是会话Cookie不在本地文件存储,只存储于内存,而本地Cookie因为设置了expire过期时间需要在本地存储 下面是白帽子讲W ...