BST—平衡树
Treap
对于treap来说, 使用随机数的方式使数据被打乱, 利用平衡树的旋转达到简化访问的目的。(初步理解)
#include <cstdio>
#include <algorithm>
#include <iostream>
#define il inline
#define rg register int
#define ll long long
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
using namespace std;
il int read()
{
int x = 0; char c; bool f = false;
while (!isdigit(c = getchar()))if (c == '-')f = true;
do
{
x = (x << 1) + (x << 3) + (c ^ 48);
}while (isdigit(c = getchar()));
return f ? -x : x;
}
const int N = 1e5 + 10;
const int inf = 1e9;
int n, tot, root;
int ch[N][2], val[N], size[N], pro[N], cnt[N];
int neww (int x)
{
val[++tot] = x;
pro[tot] = rand();
size[tot] = 1;
cnt[tot] = 1;
return tot;
}
void pushup (int x)
{
size[x] = size[ls (x)] + size[rs (x)] + cnt[x];
return ;
}
void build ()
{
root = neww (-inf);
rs (root) = neww (inf);
pushup (root);
}
void rotate (int &x, int d)
{
int son = ch[x][d ^ 1];
ch[x][d ^ 1] = ch[son][d];
ch[son][d] = x;
pushup (x); pushup (x = son);
}
void insert (int &x , int vl)
{
if (!x)
{
x = neww (vl);
return;
}
if (vl == val[x]) ++ cnt[x];
else
{
int d = val[x] < vl;
insert (ch[x][d], vl);
if (pro[x] < pro[ch[x][d]])rotate (x, d ^ 1);
}
pushup (x);
}
void del (int &x, int vl)
{
if (!x)return;
if (vl == val[x])
{
if (cnt[x] > 1)
{
--cnt[x];
pushup (x);
return;
}
if (ls (x) || rs (x))
{
if (!rs (x) || pro[ls (x)] > pro[rs (x)])
{
rotate (x, 1);
del (rs (x), vl);
}
else
{
rotate (x, 0);
del (ls (x), vl);
}
pushup (x);
}
else x = 0;
return;
}
int d = vl < val[x];
del (ch[x][d ^ 1], vl);
pushup (x);
return;
}
int rk (int x, int vl)
{
if (!x)return 0;
if (vl == val[x])return size[ls (x)] + 1;
if (vl < val[x])return rk (ls (x), vl);
return size[ls (x)] + cnt[x] + rk (rs (x), vl);
}
int vval (int x, int r)
{
if (!x)return inf;
if (r <= size[ls (x)])return vval (ls (x), r);
if (r <= size[ls (x)] + cnt[x])return val[x];
return vval (rs (x), r - size[ls (x)] - cnt[x]);
}
int pre (int vl)
{
int x = root, ti;
while (x)
{
if (val[x] < vl)ti = val[x], x = rs (x);
else x = ls (x);
}
return ti;
}
int next (int vl)
{
int x = root, ti;
while (x)
{
if (val[x] > vl)ti = val[x], x = ls (x);
else x = rs (x);
}
return ti;
}
int main()
{
build();
n = read();
for (rg i = 1; i <= n; ++i)
{
int opt = read(), x = read();
if (opt == 1)insert (root, x);
else if (opt == 2)del (root, x);
else if (opt == 3)printf ("%d\n", rk (root, x) - 1);
else if (opt == 4)printf ("%d\n", vval (root, x + 1));
else if (opt == 5)printf ("%d\n", pre (x));
else printf ("%d\n", next (x));
}
return 0;
}
18:51:24
Splay
对于Splay, 我们有规定的旋转方式使得整个树在满足二叉排序树条件的前提下变化, 以完成对数据进行修改时的时间优化, 相较来说, Splay比Treap限制更小, 更加灵活, 其树型不定, 因而被众人称为(玄学)
注意理解splay函数的意义(可证的优化)
Ps.万恶tarjan还我脑细胞
#include <cstdio> #include <algorithm> #include <iostream> #define il inline #define rg register int #define ll long long #define ls(x) ch[x][0] #define rs(x) ch[x][1] using namespace std; il int read() { int x = 0; char c; bool f = false; while (!isdigit(c = getchar()))if (c == '-')f = true; do { x = (x << 1) + (x << 3) + (c ^ 48); }while (isdigit(c = getchar())); return f ? -x : x; } const int N = 1e5 + 10; const int inf = 1e9; int n, tot, root; int ch[N][2], size[N], cnt[N], val[N], fa[N]; void cel (int x){ls (x) = rs (x) = fa[x] = size[x] = cnt[x] = val[x] = 0;} bool get (int x){return rs (fa[x]) == x;} void neww (int x) { val[++tot] = x; ls (tot) = rs (tot) = fa[tot] = 0; size[tot] = 1; cnt[tot] = 1; return; } void pushup (int x) { if (x) { size[x] = cnt[x]; if (ls (x))size[x] += size[ls (x)]; if (rs (x))size[x] += size[rs (x)]; } return; } void rotate (int x) { int f = fa[x], gf = fa[f], d = get (x); ch[f][d] = ch[x][d ^ 1]; fa[ch[f][d]] = f; ch[x][d ^ 1] = f; fa[f] = x; fa[x] = gf; //d = get (f); if (gf)ch[gf][rs (gf) == f/*d*/] = x; pushup (f); pushup (x); return; } void splay (int x) { for (rg f; f = fa[x]; rotate (x)) if (fa[f])rotate (get (x) == get (f) ? f : x); root = x; return; } void insert (int vl) { if (!root) { neww (vl); root = tot; return; } int x = root, f = 0; while (1) { if (vl == val[x]) { ++cnt[x]; pushup (x); pushup (f); splay (x); break; } f = x; x = ch[x][val[x] < vl]; if (!x) { neww (vl); fa[tot] = f; ch[f][val[f] < vl] = tot; pushup (f); splay (tot); break; } } } int rk (int vl) { int x = root, ti = 0; while (1) { if (vl < val[x])x = ls (x); else { if (ls (x))ti += size[ls (x)]; if (vl == val[x]) { splay (x); return ti + 1; } ti += cnt[x]; x = rs (x); } } } int pre () { int x = ls (root); while (rs (x))x = rs (x); return x; } int next () { int x = rs (root); while (ls (x))x = ls (x); return x; } int vval (int x) { int rt = root; while (1) { if (ls (rt) && x <= size[ls (rt)])rt = ls (rt); else { int sum = (ls (rt) ? size[ls (rt)] : 0) + cnt[rt]; if (x <= sum)return val[rt]; x -= sum; rt = rs (rt); } } } void del (int vl) { int r = rk (vl); if (cnt[root] > 1) { --cnt[root]; pushup (root); return; } if (!ls (root) && !rs (root)) { cel (root); root = 0; return; } if (!ls (root)) { int rt = root; root = rs (root); fa[root] = 0; cel (rt); return; } else if (!rs (root)) { int rt = root; root = ls (root); fa[root] = 0; cel(rt); return; } int p = pre(), rt = root; splay(p); rs (root) = rs (rt); fa[rs (rt)] = root; cel (rt); pushup (root); } int main() { n = read(); for (rg i = 1; i <= n; ++i) { int opt = read(), x = read(); if (opt == 1)insert (x); else if (opt == 2)del (x); else if (opt == 3)printf ("%d\n", rk (x)); else if (opt == 4)printf ("%d\n", vval (x)); else if (opt == 5)insert (x), printf ("%d\n", val[pre ()]), del (x); else insert (x), printf ("%d\n", val[next ()]), del (x); } return 0; }
21:56:28
2022-06-04(高考集训前夕)

浙公网安备 33010602011771号