普通平衡树 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 ...
随机推荐
- egg 提交数据 防csrf 攻击 配置
await ctx.render('from',{csrf:this.ctx.csrf}); 或者 使用中间件 ctx.state.csrf = ctx.csrf;
- js磁力线代码(非压缩,自己在压缩的版本上优化了代码,易于阅读)
拿去白嫖吧: <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=" ...
- STL-set&&multiset 集合
#include <iostream> #include <cstdio> #include <set> // 仿函数的原型 //struct greaters / ...
- Android ListView的批量处理(多选/反选/删除)
在Android开发中经常遇到使用ListView的情况,有时候需要的不仅仅是列表显示,还有长按列表进行多选,并且批量删除的情况,在这里记录一下自己的所学. 先上效果图: 几个需要用到的核心方法: / ...
- Fabric智能合约(base)
这里的智能合约仅包含Init函数和Invoke函数. 为什么一定是这两个方法? 因为在源码中的智能合约模块有这样的接口,如果要完成智能合约的相关编程,就需要实现源码中定义的接口,接口中定义了这两个方法 ...
- Android电源管理基础知识整理
前言 待机.睡眠与休眠的区别? Android开发者官网当中提到"idle states",该如何理解,这个状态会对设备及我们的程序造成何种影响? 进入Doze模式中的idle状态 ...
- py二级习题(提取文本,并计数)
with open(r"C:\Users\mike1\Desktop\practice_txt.txt","r",encoding = "gbk&qu ...
- Tomcat 后台war部署上传shell
tomcat的后台登录的两个目录为: /admin /manager/html 如果版本过高,只有采用弱密码的方式进后台: 有些tomcat采用默认的用户名和密码(用户名:admin,密码:空): 或 ...
- Chrome 浏览器相关
********* 问题 ********* localhost 通常会使用加密技术来保护您的信息.Google Chrome 此次尝试连接到 localhost 时,此网站发回了异常的错误凭据.这可 ...
- pip淘宝镜像安装
pip install virtualenvwrapper-win pip install -i https://pypi.tuna.tsinghua.edu.cn/simple virtualenv ...