zoukankan      html  css  js  c++  java
  • [学习笔记]替罪羊树

    替罪羊树是一个直接暴力插入,暴力重构的一个暴力平衡树。

    我们在插入时,如果左右儿子的大小差别太大,那么我们直接暴力重构。

    平衡因子:

    是为了判断这颗树是否平衡的一个系数,我们用\(\alpha\)表示,当\(\max{sz_l,sz_r} >= sz_x * \alpha\)时,我们对该子树重构,一般取\(\alpha = [0.5,1.0]\),普通一般取\(0.7\),如果\(\alpha\)大,则重构次数小,插入效率高,查询效率低,小反之。

    子树重构

    我们需要对这个子树重构,由于这是一颗二叉查找树,我们要保持中序遍历的一致性,所以我们需要对需要重构的子树中序遍历,然后二分递归进行重构。形象来说,就把这个子树拍扁,然后中点拉起来。

    image

    image

    插入 查询排名 和第\(k\)大数

    正常操作。

    删除

    删除时,不是直接删除,而且打一个标记,在他被重构时再删除。

    // code by fhq_treap
    #include<bits/stdc++.h>
    #define ll long long
    #define N 300005
    #define alpha 0.7
    
    inline ll read(){
        char C=getchar();
        ll A=0 , F=1;
        while(('0' > C || C > '9') && (C != '-')) C=getchar();
        if(C == '-') F=-1 , C=getchar();
        while('0' <= C && C <= '9') A=(A << 1)+(A << 3)+(C - 48) , C=getchar();
        return A*F;
    }
    
    template <typename T>
    void write(T x)
    {
        if(x < 0) {
            putchar('-');
            x = -x;
        }
        if(x > 9)
            write(x/10);
        putchar(x % 10 + '0');
        return;
    }
    
    int tot;
    
    struct P{
    	int l,r,v,sz,valid;
    	bool del;
    	inline void Newnode(int x){l = r = 0;sz = valid = 1;del = 0;v = x;}
    }t[N << 2];
    
    #define ls(o) t[o].l
    #define rs(o) t[o].r
    
    inline bool bad(int o){
    	return std::max(1.0 * t[ls(o)].sz,1.0 * t[rs(o)].sz) > alpha * t[o].sz;
    }
    
    inline void up(int u){
    	t[u].sz = t[ls(u)].sz + t[rs(u)].sz + !t[u].del;
    	t[u].valid = t[ls(u)].valid + t[rs(u)].valid + !t[u].del;
    }
    
    inline void dfs(int u,std::vector<int> & v){
    	if(!u)return ;
    	dfs(ls(u),v);
    	if(!t[u].del)v.push_back(u);
    	dfs(rs(u),v);
    }
    
    inline int build(std::vector<int> &v,int l,int r){
    	if(l >= r)return 0;
    	#define mid ((l + r) >> 1)
    	int u = v[mid];
    	ls(u) = build(v,l,mid);
    	rs(u) = build(v,mid + 1,r);
    	up(u);
    	return u;
    }
    
    inline void rebuild(int &u){
    	std::vector<int>v;
    	dfs(u,v);
    	u = build(v,0,(int)v.size());
    }
    
    inline void insert(int x,int &u){
    	if(!u){
    		u = ++ tot;
    		t[u].Newnode(x);
    		return ;
    	}
    	t[u].sz ++;t[u].valid ++;
    	if(x >= t[u].v)insert(x,rs(u));
    	else
    	insert(x,ls(u));
    	if(bad(u))
    	rebuild(u);
    	return ;
    }
    
    inline int getrank(int u,int x){
    	int ans = 1;
    	while(u){
    		if(t[u].v >= x)u = ls(u);
    		else{
    			ans += t[ls(u)].valid + !t[u].del;
    			u = rs(u);
    		}
    	}
    	return ans;
    }
    
    inline int findkth(int u,int x){
    	while(u){
    		if(!t[u].del && t[ls(u)].valid + 1 == x)
    		return t[u].v;
    		if(t[ls(u)].valid >= x)
    		u = ls(u);
    		else{
    			x -= t[ls(u)].valid + !t[u].del;
    			u = rs(u);
    		}
    	}
    }
    
    inline void Del(int u,int rk){
    	if(!t[u].del && rk == t[ls(u)].valid + 1){
    		t[u].del = 1;
    		-- t[u].valid;
    		return;
    	}
    	-- t[u].valid;
    	if(rk <= t[ls(u)].valid + !t[u].del)
    	Del(ls(u),rk);
    	else
    	Del(rs(u),rk - t[ls(u)].valid - !t[u].del);
    //	up(u);
    }
    
    int n,rt;
    
    int main(){
    	scanf("%d",&n);
    	rt = 0;
    	while(n -- ){
    		int opt,x;
    		scanf("%d%d",&opt,&x);
    		if(opt == 1)insert(x,rt);
    		if(opt == 2)Del(rt,getrank(rt,x));
    		if(opt == 3)std::cout<<getrank(rt,x)<<std::endl;
    		if(opt == 4)std::cout<<findkth(rt,x)<<std::endl;
    		if(opt == 5)std::cout<<findkth(rt,getrank(rt,x) - 1)<<std::endl;
    		if(opt == 6)std::cout<<findkth(rt,getrank(rt,x + 1))<<std::endl;
    	}
    }
    
    

    不过除了不会写错好像被fhq吊打了。

    image

    下面的是fhq。

  • 相关阅读:
    [VirtaulBox]网络连接设置
    LeetCode
    LeetCode
    LeetCode
    LeetCode-37.Sudok Solver
    LeetCode-36.Valid Sudoku
    LeetCode-52.N-Queen II
    LeetCode-51.N-Queens
    LeetCode-22.Generate Parentheses
    LeetCode-111.Mininum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/dixiao/p/15645330.html
Copyright © 2011-2022 走看看