https://www.luogu.org/problemnew/show/P3369

Splay模板

 #include<iostream>
#include<cstdio>
using namespace std;
#define MAXN 100010
int n,sons[MAXN][],f[MAXN],size[MAXN],cnt[MAXN],value[MAXN],root,Size;
inline int read(){    //快读
int x=,ff=; char c=getchar();
while(c<''||c>'') { if(c=='-') ff=-; c=getchar(); }
while(''<=c&&c<='') { x=(x<<)+(x<<)+c-''; c=getchar(); }
return x*ff;
}
inline void clear(int x){  //清除节点x
f[x]=sons[x][]=sons[x][]=size[x]=cnt[x]=value[x]=;
}
inline int get_w(int p){
return sons[f[p]][]==p;
}
inline void update(int p){
if(p){
size[p]=cnt[p];
if(sons[p][]) size[p]+=size[sons[p][]];
if(sons[p][]) size[p]+=size[sons[p][]];
}
}
inline void rotate(int x){  //旋转节点x
int fa=f[x],gfa=f[f[x]],ws=get_w(x);
sons[fa][ws]=sons[x][ws^];  //father与son
f[sons[fa][ws]]=fa;
f[fa]=x;             //father与x
sons[x][ws^]=fa;
f[x]=gfa;            //x与grandfather
if(gfa) sons[gfa][sons[gfa][]==fa]=x;
update(x);
update(fa);
}
inline void Splay(int x){    //将x旋到root
for(int fa;fa=f[x];rotate(x))
if(f[fa])
rotate(get_w(x)==get_w(fa)?fa:x);  //若x,father,grandfather三个节点呈一条直线,就旋中间的节点
root=x;
}
void insert(int x){              //插入节点
if(!root){                 //如果树为空
Size++;
f[Size]=sons[Size][]=sons[Size][]=;
size[Size]=cnt[Size]=;
value[Size]=x;
root=Size;
return;
}
int now=root,fa=;
while(){
if(value[now]==x){  //如果已有的节点值=x
cnt[now]++;    //该节点数量+1
update(now);
update(fa);
Splay(now);    //旋到root,维护平衡树
return;
}
fa=now;
now=sons[now][x>value[now]];
if(!now){    如果旋到叶子节点,新开一个点
Size++;
sons[Size][]=sons[Size][]=;
f[Size]=fa;
size[Size]=cnt[Size]=;
value[Size]=x;
sons[fa][value[fa]<x]=Size;
update(fa);
Splay(Size);
return;
}
}
}
int find_num(int x){    //找大小顺序为x的节点的值
int now=root;
while(){
if(sons[now][]&&x<=size[sons[now][]]) now=sons[now][];  //左子树大小>x,则向左子树查询
else{
int temp=(sons[now][]?size[sons[now][]]:)+cnt[now];
if(x<=temp) return value[now];    //x包含在cnt[now]中
x-=temp;
now=sons[now][];
}
}
}
int find_rank(int x){        //查询值为x的点的大小编号
int now=root,ans=;
while(){
if(x<value[now]) now=sons[now][];
else{
ans+=sons[now][]?size[sons[now][]]:;
if(x==value[now]){
Splay(now);
return ans+;
}
ans+=cnt[now];
now=sons[now][];
}
}
}
inline int find_pre(){  //root的前驱即为左子树中最靠右的点
int now=sons[root][];
while(sons[now][]) now=sons[now][];
return now;
}
inline int find_suf(){
int now=sons[root][];
while(sons[now][]) now=sons[now][];
return now;
}
void delete_node(int x){  //删除节点x
find_rank(x);      //将x旋上去
if(cnt[root]>){
cnt[root]--;
update(root);
return;
}
if(!sons[root][]&&!sons[root][]){
clear(root); root=; return;
}
if(!sons[root][]){
int last=root;
root=sons[root][];
f[root]=;
clear(last);
return;
}
if(!sons[root][]){
int last=root;
root=sons[root][];
f[root]=;
clear(last);
return;
}
int last=root,pre=find_pre();    //将前驱旋上去,此时x为pre的右儿子,直接删除即可(类似于链表)
Splay(pre);
sons[root][]=sons[last][];
f[sons[last][]]=root;
clear(last);
update(root);
}
int main()
{
n=read();
int opt,x;
while(n--){
opt=read(); x=read();
switch(opt){
case : insert(x); break;
case : delete_node(x); break;
case : printf("%d\n",find_rank(x)); break;
case : printf("%d\n",find_num(x)); break;
case : insert(x);printf("%d\n",value[find_pre()]);delete_node(x); break;
case : insert(x);printf("%d\n",value[find_suf()]);delete_node(x); break;
}
}
return ;
}

【洛谷P3369】 (模板)普通平衡树的更多相关文章

  1. 【洛谷P3369】普通平衡树——Splay学习笔记(一)

    二叉搜索树(二叉排序树) 概念:一棵树,若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值: 它的左.右子树也分别为二叉搜索树 ...

  2. 洛谷.3369.[模板]普通平衡树(Splay)

    题目链接 第一次写(2017.11.7): #include<cstdio> #include<cctype> using namespace std; const int N ...

  3. 洛谷.3369.[模板]普通平衡树(fhq Treap)

    题目链接 第一次(2017.12.24): #include<cstdio> #include<cctype> #include<algorithm> //#def ...

  4. 洛谷.3391.[模板]文艺平衡树(Splay)

    题目链接 //注意建树 #include<cstdio> #include<algorithm> const int N=1e5+5; //using std::swap; i ...

  5. 洛谷P3369 【模板】普通平衡树(Treap/SBT)

    洛谷P3369 [模板]普通平衡树(Treap/SBT) 平衡树,一种其妙的数据结构 题目传送门 题目描述 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 插入x数 删除 ...

  6. 【洛谷P3369】【模板】普通平衡树题解

    [洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...

  7. 洛谷P3369普通平衡树(Treap)

    题目传送门 转载自https://www.cnblogs.com/fengzhiyuan/articles/7994428.html,转载请注明出处 Treap 简介 Treap 是一种二叉查找树.它 ...

  8. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

  9. 绝对是全网最好的Splay 入门详解——洛谷P3369&BZOJ3224: Tyvj 1728 普通平衡树 包教包会

    平衡树是什么东西想必我就不用说太多了吧. 百度百科: 一个月之前的某天晚上,yuli巨佬为我们初步讲解了Splay,当时接触到了平衡树里的旋转等各种骚操作,感觉非常厉害.而第二天我调Splay的模板竟 ...

  10. 洛谷P3380 二逼平衡树

    线段树+平衡树 我!又!被!卡!常!了! 以前的splay偷懒的删除找前驱后继的办法被卡了QAQ 放一个在洛谷开O2才能过的代码..我太菜了.. #include <bits/stdc++.h& ...

随机推荐

  1. 《腾讯游戏人生》微信小程序开发总结

    为打通游戏人生擂台赛与线下商家的O2O衔接,同时响应时下日臻火热的微信小程序,项目团队决定也开发一款针对性的微信小程序,以此方便商家在我们平台入驻并进行擂台赛事的创建和奖励的核销,进一步推广擂台赛的玩 ...

  2. 使用openssl在命令行加密

    对于需要在应用软件中进行加密编程的开发者,通过命令行把基本的加密操作做一遍是很有意义的.openssl支持在命令行进行各种基本加密算法的操作.这些操作过程无需编程,其命令参数与程序函数调用加密的参数有 ...

  3. hibernate表关系

    1.一对一 用户表可以查分成两个表,一个userInfo.一个userLogin表 实现方式: (1)使用外键:外键+唯一性约束+非空约束 (2)公用主键:公用主键,从表的主键同时也是外键,来源于主表 ...

  4. 【Linux】安装配置JDK1.8

    第一步:下载Linux环境下的jdk1.8,请去(官网)中下载jdk的安装文件: https://www.oracle.com/technetwork/java/javase/downloads/in ...

  5. 用于模式匹配的String方法和RegExp方法

    上一节总结了创建正则表达式的语法,这一篇笔者总结了用于模式匹配的String四个方法:search().replace().match().split()以及用于模式匹配的RegExp两个方法exec ...

  6. 自动化运维与Saltstack

    一.自动化运维介绍 1.自动化运维产生背景   传统的IT运维是将数据中心中的网络设备.服务器.数据库.中间件.存储.虚拟化.硬件等资源进行统一监控,当资源出现告警时,运维人员通过工具或者基于经验进行 ...

  7. Nginx管理(一)

    一.Nginx介绍 Nginx (engine x) 是一个高性能的HTTP和反向代理服务,也是一个IMAP/POP3/SMTP服务. 1.Nginx历史和特性 Nginx是由伊戈尔·赛索耶夫为俄罗斯 ...

  8. BAT的java面试题

    公司:国内三巨头其中的一家!面试时间约在1月份左右!基本上都是在晚上,所以不影响白天上班! 一面 一面偏架构方面 1.介绍一下自己,讲讲项目经历 2.你们项目中微服务是怎么划分的,划分粒度怎么确定? ...

  9. H5前端的行业知识

    今天咱们不说代码!咱们说点行内的只是吧!! 一.前端基本技能: 会点设计,不要求精湛,处理图片,设计个小广告是要的: 精通HTML+CSS,并能快速处理各浏览器兼容问题: 熟练掌握Javascript ...

  10. ArcGIS Geodabase OBJECTID重新初始编号的间接方法

    ArcGIS Geodabase OBJECTID为Long型,随着Feature的增加和删除自动编号,均为增加.即删除Feature后,再增加该号码自动只增加不重新编号. 间接方法可以实现重新从1编 ...