普通平衡树 lg3369
在多次学习splay后,我终于理解并码出了整份代码
参考了https://tiger0132.blog.luogu.org/slay-notes的博客
具体实现原理在上面这篇博客和百度中可以查到,接下来我们看一下代码
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ls st[p].ch[0]
#define rs st[p].ch[1]
inline int read(){
int w=,f=;
char ch=getchar();
while(ch<''||ch>''){
if(ch=='-') f=-;
ch=getchar();
}
while(ch>=''&&ch<=''){
w=(w<<)+(w<<)+ch-;
ch=getchar();
}
return w*f;
}
int n,m,cnt,tot,root;
struct node{
int val,cnt,sum,ch[],f;
}st[];//val表示当前值,cnt表示出现次数,sum表示包括自己在内的子树大小,ch[0]为左儿子,ch[1]为右儿子
inline void push_up(int x){
st[x].sum=st[st[x].ch[]].sum+st[st[x].ch[]].sum+st[x].cnt;
}//上推,子树大小为左子树加右子树加自身
inline void connect(int x,int fa,int son){
st[x].f=fa;st[fa].ch[son]=x;
}//重新连接父子节点
inline bool identify(int x){
return st[st[x].f].ch[]==x;
}//判断自己是左儿子还是右儿子
inline void rotate(int x){
int y=st[x].f;int z=st[y].f;//父亲和曾祖父
int yson=identify(x);int zson=identify(y);//身份认定
int b=st[x].ch[yson^];//往上连接的节点一定是st[x].ch[yson^1]可以手画几张图推一下情况
connect(b,y,yson);connect(y,x,(yson^));connect(x,z,zson);
push_up(y);push_up(x);return;
}//rotate的实现原理在上面那个博客里有详细介绍
inline void splay(int x,int goal){
while(st[x].f!=goal){
int y=st[x].f;int z=st[y].f;
int yson=identify(x);int zson=identify(y);
if(z!=goal){
if(yson==zson) rotate(y);
else rotate(x);
}
rotate(x);
}
if(!goal) root=x;
return;
}//splay操作就是将节点向目标不断旋转
inline void insert(int x){
int now=root;int f=;
while(now&&st[now].val!=x){//原平衡树上不一定有现在查询的这个值,所以在往下跳的同时记录上一步,也就是父节点的位置
f=now;
now=st[now].ch[x>st[now].val];
}
if(now){
st[now].cnt++;//如果查询到了,并且发现已经有这个节点,就cnt++;
}
else{
tot++;now=tot;//如果发现原先没有这么个节点,就新建一个
if(f){
st[f].ch[x>st[f].val]=now;//从父亲连向儿子
}
st[now].ch[]=st[now].ch[]=;//儿子连向父亲
st[now].sum=st[now].cnt=;
st[now].f=f;st[now].val=x;
}
splay(now,);return;//将当前节点旋转到根
}
inline void find(int x){
int now=root;//本操作与上面的操作类似,找到当前值的节点,然后把其旋转到根上
if(!now) return;
while(st[now].ch[x>st[now].val]&&x!=st[now].val){
now=st[now].ch[x>st[now].val];
}
splay(now,);return;
}
inline int Next(int x,int f){//当f=0时查询的是前驱,f=1时查询的是后继
find(x);int now=root;
if(st[now].val<x&&!f) return now;
if(st[now].val>x&&f) return now;
now=st[now].ch[f];
while(st[now].ch[f^]) now=st[now].ch[f^];
return now;
}
inline void Delete(int x){//删除节点
int la=Next(x,);int ne=Next(x,);//查询该点的前驱后继
splay(la,);splay(ne,la);//现将前驱转到根,再将后继转向前驱,此时后继的左儿子就是当前要删的节点了
int now=st[ne].ch[];
if(st[now].cnt>){//如果该点的cnt>1,cnt--即可,要不就把子节点的联系断掉就好了
st[now].cnt--;
splay(now,);
}
else{
st[ne].ch[]=;
}
return;
}
inline int k_th(int x){//查询第k大
int now=root;
if(st[now].sum<x) return false;//如果总数不够就大力返回FALSE;
while(true){
int lson=st[now].ch[];//左儿子
if(x>st[lson].sum+st[now].cnt){//如果x比左儿子的大小加上当前节点出现次数还大,就向右子树查询,记得减去之前的数值
x-=st[lson].sum+st[now].cnt;
now=st[now].ch[];
}
else if(st[lson].sum>=x){
now=lson;//如果x比左子树的大小小,就向左查询
}
else return st[now].val;//如果不属于以上两种情况就是在当前节点了
}
}
int main(){//主函数就是根据题目要求大力操作了
m=read();int i,j,k;root=;
insert(INF);insert(-INF);
while(m--){
int opt=read(),x=read();
if(opt==) insert(x);
if(opt==) Delete(x);
if(opt==){
find(x);printf("%d\n",st[st[root].ch[]].sum);
}
if(opt==){
printf("%d\n",k_th(x+));
}
if(opt==){
printf("%d\n",st[Next(x,)].val);
}
if(opt==){
printf("%d\n",st[Next(x,)].val);
}
}
return ;
}
普通平衡树这道题大概就是这样了,接下来会跟进有关题目的训练及题解。
普通平衡树 lg3369的更多相关文章
- LG3369 普通平衡树
题意 维护一些数,其中需要提供以下操作: 1.插入\(x\) 2.删除\(x\)(若有多个相同的数,只删除一个) 3.查询\(x\)的排名(排名定义为比当前数小的数的个数\(+1\)) 4.查询排名为 ...
- LG3369 【模板】普通平衡树
题意 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除x数(若有多个相同的数,因只删除一个) 查询x数的排名(排名定义为比当前数小的数的个数+1.若有多个相 ...
- [BZOJ3223]Tyvj 1729 文艺平衡树
[BZOJ3223]Tyvj 1729 文艺平衡树 试题描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区 ...
- [BZOJ3224]Tyvj 1728 普通平衡树
[BZOJ3224]Tyvj 1728 普通平衡树 试题描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个) ...
- BZOJ3223: Tyvj 1729 文艺平衡树 [splay]
3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3595 Solved: 2029[Submit][Sta ...
- [普通平衡树treap]【学习笔记】
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 9046 Solved: 3840[Submit][Sta ...
- BZOJ 3224: Tyvj 1728 普通平衡树
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 9629 Solved: 4091[Submit][Sta ...
- BZOJ 3223: Tyvj 1729 文艺平衡树
3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3628 Solved: 2052[Submit][Sta ...
- 【Splay】bzoj3223-Tyvj1729文艺平衡树
一.题目 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 ...
随机推荐
- C语言中File的应用
#C语言中规定我们使用文件必须初始化一个文件指针 FILE* pfile = NULL; #以a+追加的方式打开文件 返回值0为打开成功 int fp = fopen_s(&pfile, &q ...
- LOJ6287 诗歌
题意 给定一个排列,问是否存在\(\forall a,b,a\neq b\)满足\(2|(a+b)\)且\(\frac{a+b}{2}\)在\(a,b\)间 做法 枚举中点\(a\),即需要存在类似\ ...
- SQL Server远程数据库操作(备份、还原等)
· SQL Server远程数据库备份到本地: exp sauser/sapassword@192.168.8.233:1433/DBName file=d:/backup.dmp OWNER=sum ...
- centos7虚拟机分配静态IP但是得不到IP、不能上网一种可能的原因和解决办法
1.首先通过ifconfig查看网卡,发现网卡名称为ens33 2. 在/etc/sysconfig/network-scripts/目录下查看网络配置文件 3. 发现有ifcfg-eth0的配置文件 ...
- windows 停止和启动Redis
点击win+R 输入cmd 打开cmd窗口 然后输入命令 net stop redis 停止redis net start redis 启动redis
- jrtp 使用
jrtplib-3.11.1 使用jthread-1.3.3 # cmake 下载https://cmake.org/download/ 使用地址https://github.com/j0r1/JRT ...
- Spring Boot源码(三):去除Tomcat
Spring boot中使用的是内置的Tomcat,而不像Spring mvc那样依赖外部tomcat运行项目. spring boot中导入了Tomcat的jar包: 点进一个Spring boot ...
- openlayers轨迹播放
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 关于MySQL数据库中null的那些事
在mysql数据库中,null是一个经常出现的情况,关于mysql中的null,有哪些注意事项呢?下面简单总结归纳下,后续会不断补充. 1. is null 首先判断数据库中某一列的值是否为null, ...
- win10下以管理员身份打开hosts文件
第一步: 第二步: 第三步:先后执行两个命令cmd notepad hosts 最后一步:在记事本中修改host文件