emmmmm直接丢代码了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define ri register int
using namespace std;
const int mx = 100000 + 5;
struct in
{int sz,cnt,v;in *ch[2],*f;void su()//统计大小
    {sz = ch[0] -> sz + ch[1] -> sz + cnt;}int dir()//判断自己为左/右蛾子
    {return f -> ch[1] == this;}int cmp(int x)//判断该向哪里走
    {if(v == x)return -1;return x > v;}void setc(in *p,int d)//把这棵子树接到另一个点上
    {(ch[d] = p) -> f = this;}
}T[mx],*root,*null,*Null;
int tot;
in* newnode(in *p,int x)//建立新节点
{in *qwq = &T[++ tot];qwq -> v = x,qwq -> f = p,qwq -> cnt = qwq -> sz = 1;qwq -> ch[0] = qwq -> ch[1] = Null;return qwq;
}
void rotate(in *p)//旋转
{in *fa = p -> f;int d = p -> dir();//判断旋转方向:d^1 fa -> f -> setc(p,fa -> dir());//先把p接到它父亲的位置上 fa -> setc(p -> ch[d ^ 1],d),fa -> su();//然后把这个多出来的蛾子接到原来p在fa的位置上 p -> setc(fa,d ^ 1),p -> su();//最后把fa接在d^1这边 if(root == fa)//判断是不是更新根节点 root = p;
}
void splay(in *p,in *rt)
{if(rt == p)return ;while(p -> f != rt){if(p -> f -> f == rt){rotate(p);break;}else{if(p -> dir() == p -> f -> dir())//如果同方向,先旋转父亲,再旋转本身 rotate(p -> f),rotate(p);else//否则一直旋转本身
                rotate(p),rotate(p);}}p -> su();if(rt == null)//如果发现这个点被要求旋转到树根,则更新树根 root = p;
}
void insert(in *p,int x)//插入
{if(root == Null)//如果一个点都没有
    {root = newnode(null,x);return;//null是树根,Null是空的意思
    }while(p -> ch[p -> v < x] != Null)//不停的走,x偏小向左,偏大向右,与该点相等停下
    {if(p -> v == x)break;p = p -> ch[p -> v < x];}if(p -> v == x)//判断下是不是与该点相等
    {p -> sz ++,p -> cnt ++,splay(p,null);return;}p -> ch[p -> v < x] = newnode(p,x);//建新点 splay(p -> ch[p -> v < x],null);//只要是插入删除就splay一下维持平衡
}
in* find(int x)//查找一个点并返回它的位置
{in *rt = root;while(rt -> ch[x > (rt -> v)] != Null && x != (rt -> v))rt = rt -> ch[x > (rt -> v)];return rt;
}
in* next(int x,bool flag)//查找前驱后继
{in *rt = root,*qwq;int re;if(!flag)//前驱
    {re = 0;while(rt -> ch[0]||rt -> ch[1]){if(rt -> v >= x){if(rt -> ch[0] != Null)//太大向左走 rt  = rt -> ch[0];elsebreak;}else{if(rt -> v > re)//选取尽可能和x接近的数 re = rt -> v,qwq = rt;if(rt -> ch[1] != Null)//太小向右走 rt = rt -> ch[1];elsebreak; }}if(rt -> v < x && rt -> v > re)//与最后到达的点进行比较 re = rt -> v,qwq = rt;}else//后继,与前驱原理类似
    {re = 1000000007;while(rt -> ch[0]||rt -> ch[1]){if(rt -> v <= x){if(rt -> ch[1] != Null)rt  = rt -> ch[1];elsebreak;}else{if(rt -> v < re)re = rt -> v,qwq = rt;if(rt -> ch[0] != Null)rt = rt -> ch[0];elsebreak; }}if(rt -> v > x && rt -> v < re)re = rt -> v,qwq = rt;}return qwq;
}
void erase(int x)//删除
{in *rt = find(x);//先找到这个点 if(rt -> cnt > 1)//如果这个点上的数出现了很多次,就cnt--
    {rt -> sz --,rt -> cnt --,splay(rt,null);return;}//否则把这个点彻底删除掉 bool k = rt -> f -> ch[1] == rt;//判断该点是右蛾子还是左蛾子 if(rt -> ch[0] == Null)if(rt -> ch[1] ==Null)//啥蛾子没有就直接删掉这个点 rt -> f -> ch[k] = Null;else//如果只有一个蛾子就让它代替被删除点的位置 rt -> f -> ch[k] = rt -> ch[1],rt -> ch[1] -> f = rt -> f;elseif(rt -> ch[1] == Null)rt -> f -> ch[k] = rt -> ch[0],rt -> ch[0] -> f = rt -> f;else//否则如果左右蛾子都有的话 ,就让左蛾子顶替位置,然后把右蛾子放到左蛾子子树的最靠上的右空位(因为右蛾子的任何一个点都比做蛾子大,肯定在这棵子树的最右边)
        {in *ls = rt -> ch[0];rt -> f -> ch[k] = rt -> ch[0];rt -> ch[0] -> f = rt -> f;while(ls -> ch[1] != Null)ls = ls -> ch[1];ls -> ch[1] = rt -> ch[1];rt -> ch[1] -> f =ls;ls -> su(),splay(ls,null);}rt -> f -> su();splay(rt -> f,null);
}
int ask(int x)//查找一个数的排名,利用二叉搜索树本身左小右大的性质
{if(root == Null)return 0;in *rt = root;int re = 0;while(rt -> v != x)//直到找到这个数为止
    {bool fl = x > rt -> v;if(fl == 1)re += rt -> ch[0] -> sz + rt -> cnt;rt = rt -> ch[fl];}re += rt -> ch[0] -> sz + 1;//最后记录下左子树的大小然后再加上它本身 splay(rt,null);return re;
}
int ask1(int x)//查找排x位的数
{in *rt = root;int num = rt -> ch[0] -> sz;while(!(x > num && x <= num + rt -> cnt))//括号里面表达式的意思为恰好找到排名为k的时候
    {if(x > num)//如果大于左子树,向右走,减去左侧排名 x -= num + rt -> cnt,rt = rt -> ch[1];else//否则向左走 rt = rt -> ch[0];num = rt -> ch[0] -> sz;}splay(rt,null);return rt -> v;
}
int n,opt,xx;
int main()
{Null = root = &T[++ tot],null = &T[++ tot],null -> ch[0] = null -> ch[1] = Null;//Null是为了初始赋值,null是根节点 scanf("%d",&n);while(n --){scanf("%d%d",&opt,&xx);if(opt == 1)insert(root,xx);//插入 if(opt == 2)erase(xx);//删除 if(opt == 3)printf("%d\n",ask(xx));//查询x的排名 if(opt == 4)printf("%d\n",ask1(xx));//查询排名为x的数 if(opt == 5)printf("%d\n",next(xx,0) -> v);//前驱 if(opt == 6)printf("%d\n",next(xx,1) -> v);//后继
    }
}

转载于:https://www.cnblogs.com/Loi-dfkdsmbd/p/8449498.html

【洛谷P3369】普通平衡树(splay)相关推荐

  1. [洛谷P3391] 文艺平衡树 (Splay模板)

    初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...

  2. 洛谷P3369 普通平衡树

    刚学平衡树,分别用了Splay和fhq-treap交了一遍. 这是Splay的板子,貌似比较短? Splay #include <iostream> #include <cstdio ...

  3. 洛谷P3391文艺平衡树(Splay)

    题目传送门 转载自https://www.cnblogs.com/yousiki/p/6147455.html,转载请注明出处 经典引文 空间效率:O(n) 时间效率:O(log n)插入.查找.删除 ...

  4. 洛谷 P3391 文艺平衡树

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

  5. 浅尝无旋Treap (基于洛谷P3391 文艺平衡树)

    说是浅尝吧,确实也挺浅的,完全是基于下面这道题写的↓ 洛谷P3391 自己去看题,我是懒得粘了... 分析 其实也没有什么好分析的,这就是一道Splay树的模板题,解决一般的Treap不能解决的区间维 ...

  6. 【洛谷P3369】 (模板)普通平衡树

    https://www.luogu.org/problemnew/show/P3369 Splay模板 1 #include<iostream> 2 #include<cstdio& ...

  7. 洛谷P3369 【模板】普通平衡树(STL做法:vectormultiset)

    problem solution1 - AC vector可以AC.lower_bound找第一个大于等于x的,upper_bound找第一个大于x的. #include<bits/stdc++ ...

  8. 洛谷P3960 列队(Splay)

    传送门 感觉自己好久不打数据结构已经完全不会了orz-- 据说正解树状数组?然而并不会 首先考虑一下每一次操作,就是把一个人从这一行中取出并放到行的最后,再从最后一列取出放到列的最后 那么这两种操作其 ...

  9. 洛谷 P2596 [ZJOI2006]书架 (splay)

    题目描述 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些 ...

最新文章

  1. SAP打印机原理、打印配置及打印操作
  2. 天翼云从业认证(3.4)云数据库
  3. 丑憨批的爬虫笔记2(爬虫引发的问题+robots协议)
  4. java : enum、创建文件和文件夹、删除文件和文件夹、获得项目绝对路径、写入数据到excel中、java代码中两种路径符号写法、读取、写入text文件...
  5. 转换实体类_利用Java反射机制进行Map和JavaBean间转换
  6. 禁用计算机f1-f12,win10禁用F1至F12热键转为功能键的技巧
  7. UI 实用素材|可视化后台系统UI视觉界面
  8. linux vi 编辑器用法
  9. php all函数,PHP 函数 preg_match_all()
  10. guns使用注意问题
  11. python简单应用_python之Click的简单应用
  12. javaee版eclipse导包出现未找到类问题
  13. layui文档,镜像站
  14. 什么是射频信号发生器?信号发生器具有哪些特点?(二)
  15. gunicorn简介、架构、安装与配置
  16. 在Centos7上安装Docker
  17. java scavenge_Java虚拟机(JVM)垃圾回收器Parallel Scavenge收集器 - Break易站
  18. flv f4v mp4 视频播放器代码
  19. Redis中setex与setnx的区别?
  20. 适合理工直男的钟平老师逻辑英语学习笔记

热门文章

  1. 入门Qt——hello, world
  2. Linux日志系统-08:定时执行脚本
  3. Linux日志系统-03:logrotate主配置文件详解
  4. org.apache.ibatis.binding.BindingException原因总结
  5. SVN更新后显示的U与G是什么意思?
  6. centos7安装pyenv
  7. linux redhat 红帽 centos 命令格式
  8. javaweb回顾第二篇tomcat和web程序部署
  9. iterm2 mac链接linux工具 桌面程序Transmit
  10. 《ArcGIS Engine+C#实例开发教程》第一讲桌面GIS应用程序框架的建立