BZOJ[3224] Tyvj 1728 普通平衡树

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3224

用Splay搞了一发….

(以下摘自我二逼平衡树那道题)

对于Splay删除操作,我询问了一些dalao的做法,这里选择了一个比较高效的,即将它的前驱Splay到根,他的后继Splay到根的右儿子,直接操掉根右儿子的左儿子即可

插入过程中,要在插入结束将插入的点Splay到根,维护平衡性,在Insert没递归结束会导致回溯出错,这里写了个AddNew函数,过程是插入->旋转,保证Splay操作是在回溯结束后

在Splay时根的指针可能出现混乱,我采用了比较傻逼的方式,传参数的时候加一个x1代表是哪个线段树的节点,Splay结束后直接更新就好(可能会有更方便的方法吧…)
具体操作:
1.找出这个点的前驱后继,如果都不为空就直接日右儿子的左儿子
2.如果前驱为空,代表这个数就是最小的了,把它的后继转到根,日掉根的左儿子
3.如果后继为空,代表这个数是最大的,把它的前驱转到根,日掉根的右儿子
4.日掉就是看这个点代表数的个数是否大于1,大于1就直接减掉一个,否则把它赋成null
(UPD 2018/3/8:优化了代码复杂度)
代码如下:

#include<algorithm>
#include<ctype.h>
#include<cstdio>
#define INF 2147483647
using namespace std;
inline int read(){int x=0,f=1;char c;do c=getchar(),f=c=='-'?-1:f; while(!isdigit(c));do x=(x<<3)+(x<<1)+c-'0',c=getchar(); while(isdigit(c));return x*f;
}
int n,t,x;
struct Node{Node *fa,*ch[2];int x,cnt,siz;Node(int);inline int dir(){if(this==fa->ch[0]) return 0;if(this==fa->ch[1]) return 1;return -1;}inline int cmp(int k){if(k==x) return -1;return k<x?0:1;}inline void maintain(){siz=cnt+ch[0]->siz+ch[1]->siz;return;}
}*root,*null,*tmp;
Node::Node(int _):x(_){siz=cnt=1;ch[0]=ch[1]=fa=null;
}
inline void init(){null=new Node(-1);null->siz=null->cnt=0;null->ch[0]=null->ch[1]=null->fa=null;root=null;
}
inline void Rotate(Node *x,int d){Node *k=x->ch[d^1];x->ch[d^1]=k->ch[d];if(x->ch[d^1]!=null) x->ch[d^1]->fa=x;k->ch[d]=x;if(x->fa!=null) x->fa->ch[x->dir()]=k;k->fa=x->fa;x->fa=k;x->maintain();k->maintain();
}
inline void Splay(Node *x,Node *y){while(x->fa!=y){if(x->fa->fa!=y && x->dir()==x->fa->dir())Rotate(x->fa->fa,x->dir()^1);Rotate(x->fa,x->dir()^1);}if(y==null) root=x;
}
void Insert(int k,Node *&x,Node *fa){if(x==null){x=new Node(k);x->fa=fa;tmp=x;return;}int d=x->cmp(k);if(!~d){x->cnt++;x->siz++;tmp=x;}else{Insert(k,x->ch[d],x);x->maintain();}
}
inline void AddNew(int x){Insert(x,root,null);Splay(tmp,null);
}
Node* LowerPointer(Node *x,int k){if(x==null) return null;if(x->x>=k) return LowerPointer(x->ch[0],k);Node *t=LowerPointer(x->ch[1],k);return t==null?x:t;
}
Node* UpperPointer(Node *x,int k){if(x==null) return null;if(x->x<=k) return UpperPointer(x->ch[1],k);Node *t=UpperPointer(x->ch[0],k);return t==null?x:t;
}
Node *reduce(Node *&x){if(x->cnt>1){x->cnt--;x->siz--;return x;}return null;
}
inline void Delete(int k){Node *a=LowerPointer(root,k),*b=UpperPointer(root,k);if(a==null && b==null){root=reduce(root);return;}if(a==null){Splay(b,null);root->ch[0]=reduce(root->ch[0]);root->maintain();return;}if(b==null){Splay(a,null);root->ch[1]=reduce(root->ch[1]);root->maintain();return;}Splay(a,null);Splay(b,a);root->ch[1]->ch[0]=reduce(root->ch[1]->ch[0]);root->ch[1]->maintain();root->maintain();return;
}
int Rank(int k,Node *x){if(k==x->x) return x->ch[0]->siz+1;int d=x->cmp(k);return Rank(k,x->ch[d])+(d?x->ch[0]->siz+x->cnt:0);
}
int K_th(int k,Node *x){if(x==null) return 0;if(x->ch[0]->siz<k && x->ch[0]->siz+x->cnt>=k) return x->x;int d=k<=x->ch[0]->siz?0:1;return K_th(k-(d?x->ch[0]->siz+x->cnt:0),x->ch[d]);
}
int main(){init();n=read();for(int i=1;i<=n;i++){t=read();x=read();switch(t){case 1: AddNew(x); break;case 2: Delete(x); break;case 3: printf("%d\n",Rank(x,root)); break;case 4: printf("%d\n",K_th(x,root)); break;case 5: printf("%d\n",LowerPointer(root,x)->x); break;case 6: printf("%d\n",UpperPointer(root,x)->x); break;}}
return 0;
}

Duan2baka的Splay模板!(二叉搜索树)相关推荐

  1. 模板:二叉搜索树平衡树

    文章目录 前言 二叉搜索树 代码 treap 代码 splay 开点 旋转 splay 插入 查找第k大元素 查找给定元素的排名 前驱&后继 删除 完整代码 练习总结 前言 终于开始学这个东西 ...

  2. 真c++ 从二叉树到红黑树(3)之二叉搜索树BST

      此文章为从二叉树到红黑树系列文章的第三节,主要介绍介绍二叉搜索树BST,为AVL和RedBlack打下基础 文章目录 一.前面文章链接~(点击右边波浪线可以返回目录) 二.二叉搜索树BST的定义~ ...

  3. 清华邓俊辉数据结构学习笔记(4) - 二叉搜索树、高级搜索树

    第七章 二叉搜索树 (a)概述 循关键码访问:数据项之间,依照各自的关键码彼此区分(call-by-key),条件是关键码之间支持大小比较与相等比对,数据集合中的数据项统一地表示和实现为词条entry ...

  4. 消除左递归实验代码_「leetcode」108. 构造二叉搜索树【递归】【迭代】详解!

    构造二叉搜索树,一不小心就平衡了 ❞ 108.将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树 ...

  5. LeetCode Algorithm 530. 二叉搜索树的最小绝对差

    530. 二叉搜索树的最小绝对差 Ideas 前几天一直刷链表题,这道题刚看到的时候还有点懵,第一个想到的方法竟然是全排列,脑子瓦特了. 二叉树的题目基本上都得跟(前/中/后)序遍历扯点关系,一看是没 ...

  6. 消除左递归实验代码_「leetcode」669. 修剪二叉搜索树:【递归】【迭代】详解!

    单纯移除一个节点那还不够,要修剪! ❞ 669. 修剪二叉搜索树 题目链接:https://leetcode-cn.com/problems/trim-a-binary-search-tree/ 给定 ...

  7. 二叉搜索树(二叉排序树)

    全部数据结构.算法及应用课内模板请点击:https://blog.csdn.net/weixin_44077863/article/details/101691360 二叉搜索树(二叉排序树)(bin ...

  8. C++ 二叉搜索树的实现

    二叉树搜索树 二叉搜索树,同时也称为二叉排序树.它可以为一个空树,或者满足二叉搜索树的性质 如果左子树不为空时,左子树的值小于双亲结点 如果右子树不为空时,右子树的值大于双亲结点 同时,它的左右子树也 ...

  9. 中级C++:二叉搜索树、key-Value模型

    文章目录 二叉搜索树的特征 搜索树的添加 搜索树的遍历打印 搜索树的查找 搜索二叉树的删除 递归版本 递归插入 递归查找 递归删除 接口总览 key-Value 模型 基建 key-Value的添加 ...

  10. 数据结构--伸展树(伸展树构建二叉搜索树)-学习笔记

    2019/7/16更新:封装SplayTree进入class:例题:http://poj.org/problem?id=3622 一个伸展树的板子: #include<stdio.h> # ...

最新文章

  1. 《Log4j 2 官方文档》Scripts
  2. centos 7 关闭 firewall、iptables
  3. tb计算机存储单位_如何节省数TB的云存储
  4. 操作系统宕机,MySQL数据找回记录
  5. android Camera 中的相关概念
  6. javascript 学习总结(五)Function对象
  7. 现实世界的Windows Azure: 采访LexisNexis的Marc Slovak 和 Manish Bhargava
  8. Java第十二次作业:继承与抽象类解决工人与学生的问题,抽象类实例。抽象类作用——为多态创造了可能。抽象类的作用总结...
  9. QQ魔法卡片辅助工具外挂silverlight版
  10. unc0ver 越狱工具来袭,支持iOS11.0~iOS14.8稳定越狱 更新至V8.0.2 支持 A7-A14
  11. coreseek拼音检索第三版性能测试
  12. 搜索引擎优化(step-by-step)
  13. 更新AirPods Max新固件版本以及该如何查看版本号
  14. 罗克韦尔AB PLC ControlLogix PLC的介绍和选型
  15. 北理工嵩天Python语言程序设计笔记(10 Python计算生态概览)
  16. gwo算法matlab源代码,智能优化算法应用:基于GWO优化BP神经网络 - 附代码
  17. 微信支付回调通知实现
  18. 在字符串中查找指定字符串
  19. 【PMP认证考试之个人总结】第 7 章 项目质量管理
  20. grafana+prometheus+node_exporter Window笔记

热门文章

  1. 【文学】大一上学期总结
  2. solr 安装和使用
  3. 【配电网重构】基于yalmip求解含sop+二阶锥配电网重构附matlab代码
  4. Namecheap域名如何购买?步骤和注意事项附优惠码
  5. C# 解析dat文件
  6. Linux入门【第二回】 基本指令(相对路径,绝对路径)
  7. C语言数组练习-查找整数
  8. android 探究marginLeft、marginStart、marginRight、marginEnd
  9. java词频统计简单带代码_简单的词频统计代码实现(PDF格式)
  10. 爱国者布局智能硬件,空探系列PM2.5检测仪“嗅霾狗”大曝光