平衡树模板

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

  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

时间: 2024-08-14 11:46:21

平衡树模板的相关文章

HDU The kth great number 优先队列、平衡树模板题(SBT)

The kth great number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) [Problem Description] Xiao  Ming  and  Xiao  Bao  are  playing  a  simple  Numbers  game.  In  a  round  Xiao  Ming  can choose  to  write  down 

洛谷3391 文艺平衡树 平衡树模板95

上次被火星人prefix吊打,突然发现已经不会写splay了 于是来道模板题 区间反转? 打一些lazy标记,感觉和线段树没有差太多,而且交换左右儿子这操作真是妙 lazy标记 下传的时间要注意有些东西会变 1 #include <bits/stdc++.h> 2 #define N 500000 3 #define mid (l+r>>1) 4 using namespace std; 5 int n,m,x,y; 6 struct spla 7 { 8 int fa[N],c[

平衡树模板 bzoj 3224

program t3224; var tr:array[-1..1000000,1..2] of int64; num,fa,size,quan:array[-1..1000000] of int64; i,n,sz,rt:longint; x,y:int64; function judge(a:boolean):longint; begin if a then exit(1) else exit(2); end; procedure rotate(k:longint); var f,ff,lr

各种平衡树收集(收集控(‐^▽^‐))\平衡树模板题的各种花式做法QAQ

非旋转treap!!!(FHQ Treap) 递归版Splay(无需维护父指针) Scapegoat _ Tree——替罪羊树(一只(棵)特立独行的猪(树)) 宗法树(平衡线段树\finger_tree) 权值线段树/动态开点???(怎么混进来一棵线段树,神奇的玩意) 树状数组+二分??(怎么又混进来一个树状数组,貌似跟楼上差不多) PBDS(STL大法好) Leafy_tree(貌似用处不大) 01Tree(最坏32倍空间,再见) 原文地址:https://www.cnblogs.com/me

1500. [NOI2005]维修数列【平衡树-splay】

Description 请写一个程序,要求维护一个数列,支持以下 6 种操作: 请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格 Input 输入的第1 行包含两个数N 和M(M ≤20 000),N 表示初始时数列中数的个数,M表示要进行的操作数目. 第2行包含N个数字,描述初始时的数列. 以下M行,每行一条命令,格式参见问题描述中的表格. 任何时刻数列中最多含有500 000个数,数列中任何一个数字均在[-1 000, 1 000]内. 插入的数字总数不超过4 000 000个,

平衡树代码总结

这里给出博主的几种平衡树模板代码 vector 代码: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define rd(x) x=read() using namespace std; int n; vector<int>v; inline int read() { int f=1,x=0;char s=getchar(); while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar

0x46蓝书习题:普通平衡树

Treap/平衡二叉树 蓝书习题:普通平衡树 这道题是一道平衡树模板题,可以用多种解法,这里用最简单的Treap,下面简单说一下各种操作的思路 添加: 当要添加一个值时,先判断所要加入的以p为根节点的子树是否为空,为空添加新的节点:New(val). 当然平衡树,当加入新节点后,子节点dat变得大于a[p].dat时,要旋转,左旋右旋见代码,好理解. void Insert(int &p,int val){ if(!p){ p=New(val); return; } if(val==a[p].v

[知识点]Treap 指针实现

其实平衡树这个东东,我原来也是打过那么几遍的,而且三种基本的都打过了.但是呢,当时内心抵触指针,于是就用的网上的数组平衡树模板 理解起来倒是没什么问题,无奈码量略大T_T 然后就有一段时间没打平衡树了.这两天刷数据结构专题,发现一道 [HNOI 2012]永无乡 需要建多颗平衡树. 我靠!这是对我的数组平衡树的毁灭性的打击啊!! 于是狠了狠心,学指针打法! 然后hww神牛为我提供了他的板子.照着打了不到一个小时,发现指针实现的话,码量灰常小的,而且也很好理解的! 于是乎我现在满心欢喜.不过悲催的

20160529~20160604 13

蒟蒻Yzm 20160530 bzoj2333 http://www.lydsy.com/JudgeOnline/problem.php?id=2333 题意: 有N个节点,M个操作:连接两个节点.单个节点的权值增加v.节点所在的连通块的所有节点的权值增加v.所有节点的权值增加v.询问节点当前的权值.询问节点所在的连通块中权值最大的节点的权值.询问所有节点中权值最大的节点的权值. N,M≤300000 代码: 1 #include <cstdio> 2 #include <cstring