平衡树
作者:互联网
本人现已经学过,打过 没背过 的平衡树有 :
1.有旋treap
2.无旋treap
3.splay
现在想总结一下各平衡树
一,有旋treap
是oier常用且较短较好理解的平衡树, 重点的操作是左旋和右旋
思想大概是通过随机数维护一个BST, 并通过左旋和右旋使其保持平衡
上代码:
点击查看代码
#define combo void
#define eafoo int
#define ls(x) (tree[x].cl[0])
#define rs(x) (tree[x].cl[1])
#define val(x) (tree[x].val)
#define cnt(x) (tree[x].cnt)
#define data(x) (tree[x].data)
#define size(x) (tree[x].size)
struct Balance_tree
{
struct treap
{
int cl[2], val, data, cnt, size;
}tree[maxn];
int root, tot;
Treap()
{
srand((unsigned) time(NULL));
newPoint(-INFFF), newPoint(INFFF);
root = 1, rs(1) = 2;
pushup(root);
return;
}
combo pushup(int rt)
{
return (combo)(size(rt) = size(ls(rt)) + size(rs(rt)) + cnt(rt));
}
eafoo newPoint(int val)
{
val(++ tot) = val, data(tot) = rand(), cnt(tot) = size(tot) = 1;
return tot;
}
combo zrg(int& rt)
{//右旋 zig
int v = ls(rt);
ls(rt) = rs(v), rs(v) = rt, rt = v;
return (combo)(pushup(rs(rt)), pushup(rt));
}
combo zlg(int& rt)
{//左旋 zag
int v = rs(rt);
rs(rt) = ls(v), ls(v) = rt, rt = v;
return (combo)(pushup(ls(rt)), pushup(rt));
}
eafoo GetRankByVal(int rt, int val)
{
if(rt == 0)return 0;
if(val == val(rt))return size(ls(rt)) + 1;
if(val < val(rt))return GetRankByVal(ls(rt), val);
return GetRankByVal(rs(rt), val) + size(ls(rt)) + cnt(rt);
}
eafoo GetValByRank(int rt, int rank)
{
if(rt == 0)return INFFF;
if(size(ls(rt)) >= rank)return GetValByRank(ls(rt), rank);
if(size(ls(rt)) + cnt(rt) >= rank)return val(rt);
return GetValByRank(rs(rt), rank - size(ls(rt)) - cnt(rt));
}
combo insert(int& rt, int val)
{
if(rt == 0)
{
rt = newPoint(val);
return;
}
if(val == val(rt))
{
cnt(rt) ++, pushup(rt);
return;
}
if(val < val(rt))
{
insert(ls(rt),val);
if(data(rt) < data(ls(rt)))
zrg(rt);
}
else
{
insert(rs(rt),val);
if(data(rt) < data(rs(rt)))
zlg(rt);
}
pushup(rt);
return;
}
eafoo getPre(int val)
{
int ans = 1, rt = root;
while(rt)
{
if(val == val(rt))
{
if(ls(rt) > 0)
{
rt = ls(rt);
while(rs(rt) > 0)
rt = rs(rt);
ans = rt;
}
break;
}
if(val(rt) < val && val(rt) > val(ans))ans = rt;
rt = val < val(rt) ? ls(rt) : rs(rt);
}
return val(ans);
}
eafoo getNext(int val)
{
int ans = 2, rt = root;
while(rt)
{
if(val == val(rt))
{
if(rs(rt) > 0)
{
rt = rs(rt);
while(ls(rt) > 0)
rt = ls(rt);
ans = rt;
}
break;
}
if(val(rt) > val && val(rt) < val(ans))ans = rt;
rt = val < val(rt) ? ls(rt) : rs(rt);
}
return val(ans);
}
inline combo deletee(int& rt, int val)
{
if(rt == 0)return;
if(val == val(rt))
{
if(cnt(rt) > 1)
{
cnt(rt)--, pushup(rt);
return;
}
if(ls(rt) || rs(rt))
{
if(rs(rt) == 0 || data(ls(rt)) > data(rs(rt)))
zrg(rt), deletee(rs(rt), val);
else zlg(rt), deletee(ls(rt), val);
pushup(rt);
}
else rt = 0;
return;
}
val < val(rt) ? deletee(ls(rt), val) : deletee(rs(rt), val);
pushup(rt);
return;
}
}T;
二,无旋treap (fhq_treap)
是范浩强大佬发明的是最短的平衡树, 思想也比较简单, 考场上常用 虽然我怀疑我考场上想不想得起来打平衡树。
主要思想是分裂和和并, 也用上了treap的随机数。
上代码
点击查看代码
#define combo void
#define eafoo int
#define ls(x) (tree[x].cl[0])
#define rs(x) (tree[x].cl[1])
#define sz(x) (tree[x].size)
#define val(x) (tree[x].val)
#define dat(x) (tree[x].dat)
struct Balance_tree
{
struct fhq_treap
{
int cl[2], size, val, dat;
}tree[maxn];
int root, tot;
queue <int> del_list;
Balance_tree()
{
srand((unsigned)time(NULL));
newNode(-INFFF), newNode(INFFF);
root = 1, rs(root) = 2;
return;
}
eafoo newNode(int val)
{
int tmp;
if(del_list.empty())
{
tmp = ++tot;
}
else
{
tmp = del_list.front(), del_list.pop();
}
dat(tmp) = rand(), val(tmp) = val, sz(tmp) = 1;
return tmp;
}
combo pushup(int rt)
{
return (void)(sz(rt) = sz(ls(rt)) + sz(rs(rt)) + 1);
}
combo insert(int val)//加入
{
int x, y;
split_val(root, val, x, y);// 先按val分裂成两棵子树,则x子树皆<=val;
root = merge(merge(x, newNode(val)), y);//让val与x合并,再与y合并;
return;
}
combo split_val(int pos, int val, int& x, int& y)//按权值分裂
{
//在pos点时,以val分裂成x,y两棵树
if(!pos)
{
x = y = 0;
return;
}
if(val(pos) <= val)
{
x = pos, split_val(rs(pos), val, rs(pos), y);
}
else
{
y = pos, split_val(ls(pos), val, x, ls(pos));
}
pushup(pos);
return;
}
combo split_size(int pos, int siz, int& x, int& y)//按size分裂
{
//在pos点时,以siz分裂成x,y两棵树
if(!pos)
{
x = y = 0;
return;
}
if(siz > sz(ls(pos)))
{
x = pos, split_size(rs(pos), siz - sz(ls(pos)) - 1, rs(pos), y);
}
else
{
y = pos, split_size(ls(pos), siz, x, ls(pos));
}
pushup(pos);
return;
}
eafoo merge(int x, int y)//合并
{
if(!x || !y) return x + y;
if(dat(x) > dat(y))
{
rs(x) = merge(rs(x), y);
pushup(x);
return x;
}
ls(y) = merge(x, ls(y));
pushup(y);
return y;
}
combo deletee(int val)//删除
{
//先分裂出<=val的,再在x中按val-1分裂,则yy为与val相等的所有点
int x, y, z;
split_val(root, val, x, z),
split_val(x, val - 1, x, y);
// del_list.push(y);
y = merge(ls(y), rs(y));
root = merge(merge(x, y), z);
return;
}
eafoo getValbyRank(int rank)
{
++rank;
int x, y, cur;
split_size(root, rank, x, y);
cur = x;
while(rs(cur))
{
cur = rs(cur);
}
root = merge(x, y);
return val(cur);
}
eafoo getRankbyVal(int val)
{
int x, y, ans;
split_val(root, val - 1, x, y);
ans = sz(x);
root = merge(x, y);
return ans;
}
eafoo getPre(int val)
{
int x, y, cur;
split_val(root, val - 1, x, y);
cur = x;
while(rs(cur))
{
cur = rs(cur);
}
root = merge(x, y);
return val(cur);
}
eafoo getNext(int val)
{
int x, y, cur;
split_val(root, val, x, y);
cur = y;
while(ls(cur))
{
cur = ls(cur);
}
root = merge(x, y);
return val(cur);
}
}T;
三,splay
是一个很常用的平衡树,虽然代码比较长,但很稳定,且可以用来处理区间翻转问题
重要思想是splay: 把当前点认为为最常用的点并旋为根节点
点击查看代码
#define combo void
#define eafoo int
#define ekang bool
#define ls(x) (S_tree[x].cl[0])
#define rs(x) (S_tree[x].cl[1])
#define fa(x) (S_tree[x].fa)
#define sz(x) (S_tree[x].size)
#define val(x) (S_tree[x].val)
#define cnt(x) (S_tree[x].cnt)
#define lazy(x) (S_tree[x].lazy)
#define son(x,y) (S_tree[x].cl[y])
struct Balance_Tree
{
struct splay
{
int cl[2], val, fa, size, cnt, lazy;
}S_tree[maxn];
int root, tot;
inline combo newPoint(int val, int fa, int nxt)
{
return (combo)(fa(++ tot) = fa, val(tot) = val, sz(tot) = cnt(tot) = 1, son(fa, nxt) = tot);
}
inline combo pushup(int rt)
{
return (combo)(sz(rt) = sz(ls(rt)) + sz(rs(rt)) + cnt(rt));
}
inline ekang cl_fa(int rt)
{
return rs(fa(rt)) == rt;
}
inline combo connect(int rt, int y, int nxt)
{
return (combo)(son(y,nxt) = rt, fa(rt) = y);
}
inline combo rotato(int rt)
{
int fa = fa(rt), ffa = fa(fa),
fl1 = cl_fa(rt), fl2 = cl_fa(fa);
connect(son(rt, fl1 ^ 1), fa, fl1),
connect(fa, rt, fl1 ^ 1),
connect(rt, ffa, fl2);
pushup(fa), pushup(rt);
return;
}
inline combo splay(int x, int y)
{
y = fa(y);
while(fa(x) != y)
{
if(fa(fa(x)) == y)
rotato(x);
else if(cl_fa(x) == cl_fa(fa(x)))
rotato(fa(x)), rotato(x);
else rotato(x), rotato(x);
}
if(y == 0)
{
root = x;
connect(x, 0, 1);
}
return;
}
inline combo updata(int val)
{
if(root == 0){
newPoint(val, 0, 1);
root = tot;
return;
}
int now = root;
while(1)
{
sz(now) ++;
if(val(now) == val)
{
cnt(now) ++, splay(now, root);
return;
}
int nxt = val(now) < val, son = son(now, nxt);
if(!son)
{
newPoint(val, now, nxt), splay(tot, root);
return;
}
now = son;
}
return;
}
inline eafoo find(int val)
{
int now = root;
while(1)
{
if(! now)
return 0;
if(val(now) == val)
{
splay(now, root);
return now;
}
int nxt = val(now) < val, son = son(now, nxt);
now = son;
}
}
inline combo deletee(int val)
{
int now = find(val);
if(! now)
return;
if(cnt(now) > 1)
return (combo)(cnt(now) --, sz(now) --);
if(! ls(now) && ! rs(now))
return (combo)(root = 0);
if(!ls(now))
return (combo)(root = rs(root), fa(root) = 0);
if(!rs(now))
return (combo)(root = ls(root), fa(root) = 0);
else {
int pos = ls(now);
while(rs(pos))
pos = rs(pos);
splay(pos, root);
connect(rs(now), pos, 1);
pushup(pos);
return;
}
}
inline int GetRankByVal(int val)
{
int now = root, s = 0;
while(now)
{
if(val(now) == val)
{
splay(now, root);
return sz(ls(now)) + 1;
}
if(val(now) < val)
s += sz(ls(now)) + cnt(now), now = rs(now);
else now = ls(now);
}
return s + 1;
}
inline int GetValByRank(int k)
{
int now = root;
while(1)
{
int used = sz(now) - sz(rs(now));
if(k > sz(ls(now)) && k <= used)
break;
if(k > used)
k -= used, now = rs(now);
else now = ls(now);
}
splay(now, root);
return val(now);
}
inline int getPre(int val)
{
int ans = - INFFF, now = root;
while(now)
{
if(val(now) < val && val(now) > ans)
ans = val(now);
if(val > val(now))
now = rs(now);
else if(val == val(now))
return val;
else now=ls(now);
}
return ans;
}
inline int getNext(int val)
{
int ans = INFFF, now = root;
while(now)
{
if(val(now) > val && val(now) < ans)
ans = val(now);
if(val < val(now))
now = ls(now);
else if(val == val(now))
return val;
else now = rs(now);
}
return ans;
}
}S;
维护区间时,不用其存点,以一个类似于线段树的方式维护区间端点
点击查看代码
#define combo void
#define eafoo int
#define ekang bool
#define ls(x) (S_tree[x].cl[0])
#define rs(x) (S_tree[x].cl[1])
#define fa(x) (S_tree[x].fa)
#define sz(x) (S_tree[x].size)
#define val(x) (S_tree[x].val)
#define cnt(x) (S_tree[x].cnt)
#define lazy(x) (S_tree[x].lazy)
#define son(x,y) (S_tree[x].cl[y])
struct Balance_tree
{
struct splay
{
int cl[2], val, fa, size, cnt, lazy;
}S_tree[maxn];
int root, tot;
inline combo pushup(int rt)
{
return (combo)(sz(rt) = sz(ls(rt)) + sz(rs(rt)) + 1);
}
inline combo pushdown(int rt)
{
if(lazy(rt))
{
int& lc = ls(rt), & rc = rs(rt);
swap(lc, rc);
lazy(lc) ^= 1, lazy(rc) ^= 1, lazy(rt) = 0;
}
return;
}
inline combo build(int& rt, int l, int r)
{
if(l > r)return ;
int mid = (l + r) >> 1;
if(mid < rt)
ls(rt) = mid;
else rs(rt) = mid;
fa(mid) = rt, sz(mid) = 1;
if(l == r)return;
build(mid, l, mid - 1), build(mid, mid + 1, r);
pushup(mid);
}
inline combo rotate(int rt, int& k){//将x旋转至他爹那儿
int y = fa(rt), z = fa(y),
fl = rs(y) == rt;
if(y == k)
k = rt;
else son(z,rs(z) == y) = rt;
fa(son(rt, fl ^ 1)) = y, fa(y) = rt,fa(rt) = z,
son(y, fl) = son(rt, fl ^ 1), son(rt, fl ^ 1) = y;
pushup(rt), pushup(y);
return;
}
inline combo splay(int rt, int& k)
{//将rt旋转到k那儿
while(rt != k)
{
int y = fa(rt), z = fa(y);
if(y != k)
{
if((ls(z) == y) ^ (ls(y) == rt))
rotate(rt, k);
else rotate(y, k);
}
rotate(rt, k);
}
return;
}
inline eafoo select(int& rt, int k)
{
pushdown(rt);
//cerr<<rt<<endl;
int sum = sz(ls(rt)) + 1;
if(sum == k)return rt;
if(sum > k)
return select(ls(rt), k);
else return select(rs(rt), k - sum);
}
inline combo rever(int l, int r)
{
splay(l, root), splay(r, rs(l));
lazy(ls(r)) ^= 1;
}
inline combo print(int rt)
{
pushdown(rt);
if(ls(rt)) print(ls(rt));
if(2 <= rt && rt <= n + 1)
printf("%lld ", rt - 1);
if(rs(rt)) print(rs(rt));
return;
}
}S;
完
标签:rt,return,val,int,ls,平衡,now 来源: https://www.cnblogs.com/liyikang/p/16428721.html