ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

平衡树

2022-06-30 22:34:06  阅读:146  来源: 互联网

标签:rt return val int ls 平衡 now


本人现已经学过,打过 没背过 的平衡树有 :

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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有