首页 > 其他 > 详细

平衡树Splay

时间:2019-11-10 16:15:02      阅读:88      评论:0      收藏:0      [点我收藏+]

LuoguP3369

这道题啊。。。

一开始学习的时候遇到了一篇讲的超级好的博客:rentenglong 的博客

这篇大家一定要去瞅瞅,讲的炒鸡详细(就是代码有点锅。。。)

后来找到一份和TA码风差不多的,才完善了一哈qwq

不过最终还是过了

Code:

技术分享图片
  1 #include <bits/stdc++.h>
  2 #define root e[0].son[1]
  3 using namespace std;
  4 int read() {
  5     int re = 0, f = 1;
  6     char ch = getchar();
  7     while (ch < 0 || ch > 9) {if (ch == -) f = -f; ch = getchar();}
  8     while (0 <= ch && ch <= 9) {re = re * 10  + ch - 0; ch = getchar();}
  9     return re * f;
 10 }
 11 const int N = 1e5 + 3;
 12 const int INF = 1e7 + 3;
 13 int n, cnt;
 14 struct node{
 15     int v, father;//储存键值,父亲节点 
 16     int son[2];//存储左右孩子,son[0]为左,son[1]为右 
 17     int sum;//存储这个节点子树共有多少 元素 (元素包括sum + recy) 
 18     int recy;//存储相同键值重复多少次 
 19 }e[N];
 20 void update(int x) {//合并 
 21     e[x].sum = e[e[x].son[0]].sum + e[e[x].son[1]].sum + e[x].recy;
 22 }
 23 int identify(int x) {//确定当前节点与父亲节点的关系 
 24     return e[e[x].father].son[0] == x ? 0 : 1;
 25 }
 26 void connect(int x, int fa, int son) {//连接两个节点 
 27     e[x].father = fa;
 28     e[fa].son[son] = x;
 29 }
 30 void rotate(int x) {//核心函数之一,旋转 
 31     int y = e[x].father;
 32     int mroot = e[y].father;
 33     int mrootson = identify(y);
 34     int yson = identify(x);
 35     int B = e[x].son[yson ^ 1];
 36     connect(B, y, yson); 
 37     connect(y, x, (yson ^ 1));
 38     connect(x, mroot, mrootson);
 39     update(y);//y在上,先更新y 
 40     update(x);
 41 }
 42 void splay(int at, int to) {//核心函数 
 43     to = e[to].father;
 44     while (e[at].father != to) {
 45         int up = e[at].father;
 46         if (e[up].father == to) {
 47             rotate(at);
 48         } else if (identify(at) == identify(up)) {//当自己的父亲与爷爷在一条直线上时,先旋转父亲 
 49             rotate(up);
 50             rotate(at);
 51         } else {//不在同一直线上就旋转两次 
 52             rotate(at);
 53             rotate(at);
 54         }
 55     }
 56 }
 57 int newpoint(int v, int fa) {//添加新节点 
 58     e[++cnt].father = fa;
 59     e[cnt].v = v;
 60     e[cnt].sum = e[cnt].recy = 1;
 61     return cnt;
 62 }
 63 void Insert(int x) {
 64     int now = root;
 65     if(!root){//特判没根的情况 
 66         newpoint(x, 0);
 67         root = cnt;
 68     } else {
 69         while (true) {
 70             e[now].sum++;//经过的点子树中元素都要++ 
 71             if (e[now].v == x) {
 72                 e[now].recy++;//重复 
 73                 splay(now, root);
 74                 return;
 75             }
 76             int next = x < e[now].v ? 0 : 1;//判断该走左孩子还是右孩子 
 77             if (!e[now].son[next]) {
 78                 int add = newpoint(x, now);
 79                 e[now].son[next] = add;
 80                 splay(add, root);
 81                 return;
 82             }
 83             now = e[now].son[next];
 84         }
 85     }
 86 }
 87 int find(int v) {//查询键值为v的点的位置 
 88     int now = root;
 89     while (true) {
 90         if (e[now].v == v) {
 91             splay(now, root);//划重点,下面有用 
 92             return now;
 93         }
 94         int next = v < e[now].v ? 0 : 1;
 95         if (!e[now].son[next]) {
 96             return 0;
 97         }
 98         now = e[now].son[next];
 99     }
100 }
101 void delet(int x) {//删除节点 
102     int now = find(x);//注意find()函数中已经将x转为根节点 
103     if (!now) {
104         return;
105     }
106     if (e[now].recy > 1) {//如果有重复,直接减去即可 
107         e[now].recy--;
108         e[now].sum--;
109     } else {
110         if (!e[now].son[0] && !e[now].son[1]) {//如果没有左右孩子,说明就一个点 
111             root = 0;
112         } else if (!e[now].son[0]) {//如果没有左孩子,直接将右孩子提为根节点 
113             root = e[now].son[1];
114             e[root].father = 0;
115         } else {//左右孩子都有,先将左子树中最大的节点转到左孩子的位置,然后提为根节点,把右孩子连到该节点之下 
116             int lef = e[now].son[0];
117             while (e[lef].son[1]) {//找左子树中最大的节点 
118                 lef = e[lef].son[1];
119             }
120             splay(lef, e[now].son[0]);
121             connect(e[now].son[1], lef, 1);
122             connect(lef, 0, 1);
123             update(lef);
124         }
125     }
126 }
127 int _rank(int v) {
128     int now = find(v);//因为find()已经将v转为根节点,所以直接求即可 
129     return e[e[now].son[0]].sum + 1;
130 }
131 int arank(int x) {
132     int now = root;
133     while (true) {
134         int used = e[now].sum - e[e[now].son[1]].sum;
135         //如果x大于左子树元素,并且小于等于当前点的左子树的sum加上本节点的recy的值,那么当前的点就是要找的点 
136         //因为此时说明该x是当前节点重复值中的一个 
137         if (e[e[now].son[0]].sum < x && x <= used) {
138             splay(now, root);
139             return e[now].v;
140         }
141         if (x < used) {//小于则向左子树寻找 
142             now = e[now].son[0];
143         } else {//大于则减去该值,再向右子树寻找 
144             x -= used;
145             now = e[now].son[1];
146         }
147     }
148 }
149 int lower(int v) {//前驱 
150     int now = root;
151     int ans = -INF;
152     while (now) {
153         if (e[now].v < v && e[now].v > ans) {
154             ans = e[now].v;
155         }
156         if (v > e[now].v) {
157             now = e[now].son[1];
158         } else {
159             now = e[now].son[0];
160         }
161     }
162     return ans;
163 }
164 int upper(int v) {//后继 
165     int now = root;
166     int ans = INF;
167     while(now) {
168         if (e[now].v > v && e[now].v < ans) {
169             ans = e[now].v;
170         }
171         if (v < e[now].v) {
172             now = e[now].son[0];
173         } else {
174             now = e[now].son[1];
175         } 
176     }
177     return ans;
178 }
179 int main () {
180     n = read();
181     while (n--) {
182         int o = read();
183         int x = read();
184         if (o == 1) {
185             Insert(x);
186         } else if (o == 2) {
187             delet(x);
188         } else if (o == 3) {
189             printf("%d\n", _rank(x));
190         } else if (o == 4) {
191             printf("%d\n", arank(x));
192         } else if (o == 5) {
193             printf("%d\n", lower(x));
194         } else if (o == 6) {
195             printf("%d\n", upper(x));
196         }
197     }
198     return 0;
199 }
View Code

 

 

平衡树Splay

原文:https://www.cnblogs.com/Sundial/p/11830461.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!