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

Splay模板

  1 #include<iostream>
  2 #include<cstdio>
  3 using namespace std;
  4 #define MAXN 100010
  5 int n,sons[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],value[MAXN],root,Size;
  6 inline int read(){    //快读
  7     int x=0,ff=1; char c=getchar();
  8     while(c<'0'||c>'9') { if(c=='-') ff=-1; c=getchar(); }
  9     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
 10     return x*ff;
 11 }
 12 inline void clear(int x){  //清除节点x
 13     f[x]=sons[x][0]=sons[x][1]=size[x]=cnt[x]=value[x]=0;
 14 }
 15 inline int get_w(int p){
 16     return sons[f[p]][1]==p;
 17 }
 18 inline void update(int p){
 19     if(p){
 20         size[p]=cnt[p];
 21         if(sons[p][0]) size[p]+=size[sons[p][0]];
 22         if(sons[p][1]) size[p]+=size[sons[p][1]];
 23     }
 24 }
 25 inline void rotate(int x){  //旋转节点x
 26     int fa=f[x],gfa=f[f[x]],ws=get_w(x);
 27     sons[fa][ws]=sons[x][ws^1];  //father与son
 28     f[sons[fa][ws]]=fa;
 29     f[fa]=x;             //father与x
 30     sons[x][ws^1]=fa;
 31     f[x]=gfa;            //x与grandfather
 32     if(gfa) sons[gfa][sons[gfa][1]==fa]=x;
 33     update(x);
 34     update(fa);
 35 }
 36 inline void Splay(int x){    //将x旋到root
 37     for(int fa;fa=f[x];rotate(x))
 38      if(f[fa])
 39       rotate(get_w(x)==get_w(fa)?fa:x);  //若x,father,grandfather三个节点呈一条直线,就旋中间的节点
 40     root=x;
 41 }
 42 void insert(int x){              //插入节点
 43     if(!root){                 //如果树为空
 44         Size++;
 45         f[Size]=sons[Size][0]=sons[Size][1]=0;
 46         size[Size]=cnt[Size]=1;
 47         value[Size]=x;
 48         root=Size;
 49         return;
 50     }
 51     int now=root,fa=0;
 52     while(1){
 53         if(value[now]==x){  //如果已有的节点值=x
 54             cnt[now]++;    //该节点数量+1
 55             update(now);
 56             update(fa);
 57             Splay(now);    //旋到root,维护平衡树
 58             return;
 59         }
 60         fa=now;
 61         now=sons[now][x>value[now]];
 62         if(!now){    如果旋到叶子节点,新开一个点
 63             Size++;
 64             sons[Size][0]=sons[Size][1]=0;
 65             f[Size]=fa;
 66             size[Size]=cnt[Size]=1;
 67             value[Size]=x;
 68             sons[fa][value[fa]<x]=Size;
 69             update(fa);
 70             Splay(Size);
 71             return;
 72         }
 73     }
 74 }
 75 int find_num(int x){    //找大小顺序为x的节点的值
 76     int now=root;
 77     while(1){
 78         if(sons[now][0]&&x<=size[sons[now][0]]) now=sons[now][0];  //左子树大小>x,则向左子树查询
 79         else{
 80             int temp=(sons[now][0]?size[sons[now][0]]:0)+cnt[now];
 81             if(x<=temp) return value[now];    //x包含在cnt[now]中
 82             x-=temp;
 83             now=sons[now][1];
 84         }
 85     }
 86 }
 87 int find_rank(int x){        //查询值为x的点的大小编号
 88     int now=root,ans=0;
 89     while(1){
 90         if(x<value[now]) now=sons[now][0];
 91         else{
 92             ans+=sons[now][0]?size[sons[now][0]]:0;
 93             if(x==value[now]){
 94                 Splay(now);
 95                 return ans+1;
 96             }
 97             ans+=cnt[now];
 98             now=sons[now][1];
 99         }
100     }
101 }
102 inline int find_pre(){  //root的前驱即为左子树中最靠右的点
103     int now=sons[root][0];
104     while(sons[now][1]) now=sons[now][1];
105     return now;
106 }
107 inline int find_suf(){
108     int now=sons[root][1];
109     while(sons[now][0]) now=sons[now][0];
110     return now;
111 }
112 void delete_node(int x){  //删除节点x
113     find_rank(x);      //将x旋上去
114     if(cnt[root]>1){
115         cnt[root]--;
116         update(root);
117         return;
118     }
119     if(!sons[root][1]&&!sons[root][0]){
120         clear(root); root=0; return;
121     }
122     if(!sons[root][1]){
123         int last=root;
124         root=sons[root][0];
125         f[root]=0;
126         clear(last);
127         return;
128     }
129     if(!sons[root][0]){
130         int last=root;
131         root=sons[root][1];
132         f[root]=0;
133         clear(last);
134         return;
135     }
136     int last=root,pre=find_pre();    //将前驱旋上去,此时x为pre的右儿子,直接删除即可(类似于链表)
137     Splay(pre);
138     sons[root][1]=sons[last][1];
139     f[sons[last][1]]=root;
140     clear(last);
141     update(root);
142 }
143 int main()
144 {
145     n=read();
146     int opt,x;
147     while(n--){
148         opt=read(); x=read();
149         switch(opt){
150             case 1: insert(x); break;
151             case 2: delete_node(x); break;
152             case 3: printf("%d\n",find_rank(x)); break;
153             case 4: printf("%d\n",find_num(x)); break;
154             case 5: insert(x);printf("%d\n",value[find_pre()]);delete_node(x); break;
155             case 6: insert(x);printf("%d\n",value[find_suf()]);delete_node(x); break;
156         }
157     }
158     return 0;
159 }

转载于:https://www.cnblogs.com/yjkhhh/p/9206240.html

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

  1. 【洛谷P3369】普通平衡树(splay)

    emmmmm直接丢代码了 #include<iostream> #include<cstdio> #include<cstring> #include<str ...

  2. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  3. 洛谷·【模板】点分树 | 震波【including 点分树

    初见安-这里是传送门:洛谷P6329 [模板]点分树 | 震波 一.点分树 其实你会点分治的话,点分树就是把点分治时的重心提出来重新连城一棵树. 比如当前点是u,求出子树v的重心root后将root与 ...

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

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

  5. 洛谷P3369 普通平衡树

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

  6. 洛谷.3919.[模板]可持久化数组(可持久化线段树/平衡树)

    题目链接 //利用先前的根节点建树 想一下不难写. #include <cstdio> #include <cctype> //#define gc() getchar() # ...

  7. 洛谷.4897.[模板]最小割树(Dinic)

    题目链接 最小割树模板.具体见:https://www.cnblogs.com/SovietPower/p/9734013.html. ISAP不知为啥T成0分了.. Dinic: //1566ms ...

  8. 强连通分量:洛谷P3387 模板:缩点

    传送门 顾名思义,模板awa #include <cstdio> #include <cstring> #include <cmath> #include < ...

  9. 【后缀数组】洛谷P3809模板题

    题目背景 这是一道模板题. 题目描述 读入一个长度为 n n n 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置. ...

最新文章

  1. 东北师范大学计算机科学与技术学科评估,东北的大学最强十校,工科是真强,2所211大学无缘前十...
  2. Servlet_urlpartten配置
  3. 四大步骤做好需求调研
  4. Facebook F8|闲鱼高级技术专家参会分享
  5. ITIL-IT运维管理-概述
  6. 软件项目经理应具备的素质和条件_项目经理应具备的素质和能力
  7. 10行java代码实现email代码表白感恩节必备~
  8. HashMap的put过程
  9. 定制婚礼小程序开发功能
  10. c语言中查重,体验CCleaner查重功能,快速找出电脑中的重复文件
  11. C++-FFmpeg-(5)-2-h264-概念与名词:宏块-I-P-B帧;参数设置:ABR、CQP、CBR、CRF;码流:SPS-PPS
  12. BackTrack3 硬盘安装教程
  13. 人工优化的B2B信息发布系统
  14. paypal支付 paypal网站付款标准版问题解决
  15. RK3399驱动开发 | 15 - RTC实时时钟芯片HYM8563S调试(基于linux5.4.32内核)
  16. 线性代数学习笔记——第五十四讲——非齐次方程组解的性质
  17. python中国地图代码 上色_如何让使用python绘制中国地图并给特定地区上色?
  18. GNU Make工具(二)Phony Targets 和 FORCE
  19. HAUT OJ 1508 zp与车费
  20. 流氓软件之会声会影[彻底卸载]

热门文章

  1. 老毛桃安装WIN7原版系统
  2. C++中用TinyXML对XML文件进行解析
  3. y53拆机视频教程_vivoY53L拆机图赏
  4. 从零开始刷Leetcode——数组(532.561)
  5. 在哪里定义_定义市场的关键字:找出它们在哪里使用,以便您可以抢占该市场...
  6. 高斯过程回归python_scikit-learn中的多输出高斯过程回归
  7. 如何确定电脑主板坏了_原阳县地暖漏水如何检测
  8. floodfill算法 java_OpenCV 3 floodFill(漫水填充)、图片的放大缩小 pyrUp、pyrDown、Resize JAVA OpenCV专题学习10...
  9. apktool 反编译 java_APK文件使用ApkTool解包反编译和重新打包及签名
  10. 动态取值_软件测试|动态测试技术