普通平衡树 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 ...
随机推荐
- 【Spring】bean的作用域(@Scope) - singleton、prototype
已知spring 3+已拥有多种不同的作用域: singleton(默认).prototype.request.session.global session.(参考: spring中scope作用域( ...
- Kali Linux中Chrome浏览器不能启动的问题
kali中自带了Chromium Web Browser,我点了几次没反应.我还以为是Chrome的版本问题.于是下载了Chrome的deb包. 安装中还解决了一个包依赖问题.安装成功还是不能启动.于 ...
- Markdown数学公式如何打出回归符号
来源:https://blog.csdn.net/garfielder007/article/details/51646604 函数.符号及特殊字符 语法 效果 语法 效果 语法 效果 \bar{x} ...
- linux 下查看json 文件 使用jq工具
安装 文档 yum 安装 yum search jq yum -y install jq.x86_64 apt-get install jq jq支持查看 jq . json 文件 查看json文件 ...
- js中div显示和隐藏钮为什么页面总是跳一下到最上面
<div class="menu_left"> <ul > <li id="t1" style="background- ...
- Django-模型(二)
条件查询 字段查询 实现sql中where的功能,调用过滤器filter().exclude().get(),下面以filter()为例. 通过"属性名_id"表示外键对应对象的i ...
- JavaDay10(上)
Java learning_Day10(上) 本人学习视频用的是马士兵的,也在这里献上 <链接:https://pan.baidu.com/s/1qKNGJNh0GgvlJnitTJGqgA&g ...
- Win10如何设置休眠选项(关于睡眠、休眠、快速启动这几个伪关机功能如何设置更适合笔记本电脑?)
· Win10如何设置休眠选项(关于睡眠.休眠.快速启动这几个伪关机功能如何设置更适合笔记本电脑?) 应用场景 升级正式版win10以后,发现竟然没有休眠选项,从电源管理器里面也没有找到,有时候有些重 ...
- pandas 将多个dataframe保存为一个excel文件的多个sheet表中
# 创建文件 def create(): df1 = pd.DataFrame({"a1": [1, 2, 3], "b1": [4, 5, 6]}) df2 ...
- Django Form组件的扩展
Form组件扩展 1.用Form组件自带的正则扩展 通过Django内置的字段:Validators自定义验证规则 方式一: from django.forms import Form from dj ...