在多次学习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. [HNOI2016]网络 [树链剖分,可删除堆]

    考虑在 |不在| 这条链上的所有点上放上一个 \(x\),删除也是,然后用可删除堆就随便草掉了. // powered by c++11 // by Isaunoya #pragma GCC opti ...

  2. 转: Laravel的数据库迁移 介绍的比较清晰

    原文: https://blog.sbot.io/articles/12/Laravel-数据库迁移(Database-Migrations)操作实例 很多人可能在学习Laravel框架的时候,对La ...

  3. 一键安装最新内核并开启 BBR 脚本

    最近,Google 开源了其 TCP BBR 拥塞控制算法,并提交到了 Linux 内核,从 4.9 开始,Linux 内核已经用上了该算法.根据以往的传统,Google 总是先在自家的生产环境上线运 ...

  4. JN_0013:win10快速回桌面

    4.最后一种方法是最为实用的方法.按快捷键[windows键+D键],如下图所示,两键同时按,或者先按住windows键不放再按D键.这种方法在任何时候都是有用的,并且熟练使用后可以达到非常快的速度: ...

  5. 【Thread】java线程之对象锁、类锁、线程安全

    说明: 1.个人技术也不咋滴.也没在项目中写过线程,以下全是根据自己的理解写的.所以,仅供参考及希望指出不同的观点. 2.其实想把代码的github贴出来,但还是推荐在初学的您多亲自写一下,就没贴出来 ...

  6. 史上最深入浅出的IT术语解读

    假设你是个妹子,你有一位男朋友,与此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人.你随时可以甩了现任男友,另外一位马上就能补上.这是冷备份. 假设你是个妹子,同时和两位男性在交往,两位都是你男朋 ...

  7. [CTSC2008]网络管理 [树剖+整体二分]

    这题的复杂度可以到达惊人的\(\log^4\)据说还能跑过去(差点没吓死我 直接二分+树剖树套树(\(n \log^4 n\)) 一个\(\log\)也不少的4\(\log\) 但是我有个\(\log ...

  8. ASP.NET常用内置对象(二)Response

    response翻译为中文:响应. 将数据作为请求的结果从服务器发送到客户浏览器中,并提供有关响应的消息.它可用来在页面中输出数据,在页面中跳转,还可以传递各个页面的参数. Response对象是Sy ...

  9. pandas玩转excel-> (2)如何利用pandas读取excel数据文件

    import pandas as pd #将excel文件读到内存中,形成dataframe,并命名为peoplepeople=pd.read_excel('D:/python结果/task2/Peo ...

  10. FZU-Problem 2150 Fire Game(两点bfs)

    Fat brother and Maze are playing a kind of special (hentai) game on an N*M board (N rows, M columns) ...