在多次学习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的更多相关文章

  1. LG3369 普通平衡树

    题意 维护一些数,其中需要提供以下操作: 1.插入\(x\) 2.删除\(x\)(若有多个相同的数,只删除一个) 3.查询\(x\)的排名(排名定义为比当前数小的数的个数\(+1\)) 4.查询排名为 ...

  2. LG3369 【模板】普通平衡树

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

  3. [BZOJ3223]Tyvj 1729 文艺平衡树

    [BZOJ3223]Tyvj 1729 文艺平衡树 试题描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区 ...

  4. [BZOJ3224]Tyvj 1728 普通平衡树

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

  5. BZOJ3223: Tyvj 1729 文艺平衡树 [splay]

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3595  Solved: 2029[Submit][Sta ...

  6. [普通平衡树treap]【学习笔记】

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

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

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

  8. BZOJ 3223: Tyvj 1729 文艺平衡树

    3223: Tyvj 1729 文艺平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3628  Solved: 2052[Submit][Sta ...

  9. 【Splay】bzoj3223-Tyvj1729文艺平衡树

    一.题目 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 ...

随机推荐

  1. springboot 报错 org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type 'com.example.service.HrService' available: 有没有大佬出个主意,我找了一天,刚入门springboot

    话不多说先上图,这是启动类的配置,这里配置了@ComponentScan("我的mapper的接口") 接下来是我的项目结构截图 然后是service 的截图,我在这里加了注解@S ...

  2. warning Attribute 'showExpand' must be hyphenated

    报错翻译:警告属性“ showExpand”必须带连字符 报错原因父组件给子组件传参时,使用驼峰命名法,导致ESLint检测出语法问题,如下↓ 改成这样就ok了

  3. Linux系统之网络相关的命令

    Linux系统之网络相关的命令 网络概述 网络:通过通信介质和通信设备 将分布不同地点的两台或多台计算机,经过相应的程序实现通信switch 交换机router 路由器网络的功能:数据通信:利用网络传 ...

  4. 自适应阈值化操作:adaptiveThreshold()函数

    在图像阈值化操作中,更关注的是从二值化图像中,分离目标区域和背景区域,但是仅仅通过设定固定阈值很难达到理想的分割效果.而自适应阈值,则是根据像素的邻域块的像素值分布来确定该像素位置上的二值化阈值.这样 ...

  5. 洛谷【P2022 有趣的数】 题解

    题目链接 https://www.luogu.org/problem/P2022 题目描述 让我们来考虑1到N的正整数集合.让我们把集合中的元素按照字典序排列,例如当N=11时,其顺序应该为:1,10 ...

  6. liner-classifiers-SVM

    1支持向量机 参考看了这篇文章你还不懂SVM你就来打我 第一遍看完确实有想打死作者的冲动,但是多看几遍之后,真香~ [SVM---这可能是最直白的推导了] 个人觉得这篇文章讲的很清楚,条理清晰,数学推 ...

  7. 【巨杉数据库SequoiaDB】巨杉Tech | 巨杉数据库的并发 malloc 实现

    本文由巨杉数据库北美实验室资深数据库架构师撰写,主要介绍巨杉数据库的并发malloc实现与架构设计.原文为英文撰写,我们提供了中文译本在英文之后. SequoiaDB Concurrent mallo ...

  8. IO流学习之字符流(二)

    用字符流完成文档的复制: 测试文档: 代码1: package InputOutput; import java.io.FileReader; import java.io.FileWriter; i ...

  9. Pandas 中对列 groupby 后进行 sum() 与 count() 区别及 agg() 的使用方法

    groupby[根据哪一列][ 对于那一列].进行计算 代码演示: direction:房子朝向 view_num:看房人数 floor:楼层 计算: A 看房人数最多的朝向 df.groupby([ ...

  10. PIE-SDK For C++内存栅格数据的创建

    1.功能简介 目前在地理信息领域中数据包括矢量和栅格两种数据组织形式.每一种数据有不同的数据格式,目前PIE SDK支持多种数据格式的数据创建,下面对内存栅格数据格式的数据创建功能进行介绍. 2.功能 ...