zoukankan      html  css  js  c++  java
  • 替罪羊树

    这是一篇低质量博客

    但是笔者自己看效果可能很好(写给自己看的博客)

    一、前言

    失踪人口终于回归啦~

    替罪羊树太简单了! 以致于板题调了两天呢!

    二、讲解

    我们已经学过很多平衡树了,对于平衡树满足的特点,我就不多赘述了

    我们直接步入正题,讲解替罪羊树维持平衡的方法

    首先我们要知道怎样才算不平衡,这样我们才好修复

    直接yy:如果一个点的某一个儿子太重了,那么这棵子树就不平衡了

    上面的yy过于感性,我们来定量分析一下:

    我们引入替罪羊树专有的变量:(alpha)平衡因子

    如果重儿子的重量 (>) 整棵子树的重量 ( imes alpha),那么我们认为它不平衡

    我们一般把(alpha)定为(0.5)~(1)的数(()个人喜欢(0.7))

    别问,问就是7777777777777777

    那么如果树不平衡了怎么办呢?

    暴力重建!

    当然不是整棵树,而是不平衡的最上面的那棵子树

    比如子树(A,B)都不平衡,而子树(B)属于子树(A),那么我们要重建的是子树(A)而非子树(B),因为重建了子树(B),子树(A)依然不平衡

    由于只有插入和删除操作会影响,所以在每次插入或删除操作后,我们检查一下是否存在不平衡的子树,有则改之,无则加勉

    检查的细节是插入和删除只有一个元素,所以只需要检查 以这个元素到根的路径上的点的子树是否平衡就行了

    重建没什么好说的吧,把要重建的点拖出来重新排一下就好了

    0、结构体定义

    int son[2],val,siz,cnt,fa;
    //左右儿子(0,1) 元素值 子树大小 元素个数 当前节点的父亲
    bool exist;
    //是否存在(其实直接看cnt是否为0就好了,我码麻烦了)
    

    1、插入

    其实插入没什么好讲的

    如果存在插入的元素,(cnt++)

    不存在,找到应该放的位置,放进去就好了

    插入之后记得更新这条链上的子树大小

    2、删除

    删除有两种方法

    一是打上标记(貌似不需要打标记,只需要检查次数就好了)

    二是把它的儿子提上来

    我是前者

    找到该元素,(cnt--)

    如果(cnt==0),打上消失的标记(也可以不打,我们可以根据(cnt)是否为(0)来判断)

    记得更新这条链上的子树大小

    3、其他操作

    和其它的平衡树类似,不再展开

    关于代码:笔者首次采用了内存池的打法,个人感觉这种写法很好,值得一学(你不学我也不拦着你)

    三、练习

    板题(洛谷)

    带插入区间K小值(洛谷)

    四、代码

    板题代码

    //12252024832524
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 100005;
    const int INF = 0x3f3f3f3f; 
    int n;
    
    int Read()
    {
    	int x = 0,f = 1;char c = getchar();
    	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
    	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
    	return x * f;
    }
    void Put1(int x)
    {
    	if(x > 9) Put1(x/10);
    	putchar(x%10^48);
    }
    void Put(int x,char c = -1)
    {
    	if(x < 0) putchar('-'),x = -x;
    	Put1(x);
    	if(c >= 0) putchar(c);
    }
    template <typename T>T Max(T x,T y){return x > y ? x : y;}
    template <typename T>T Min(T x,T y){return x < y ? x : y;}
    template <typename T>T Abs(T x){return x < 0 ? -x : x;}
    
    struct ScapegoatTree
    {
    	int rt,tot,ncc[MAXN],ncctot;//根 点 内存池 内存池的点 
    	int retot,re[MAXN][2];//0 val 1 cnt
    	double alpha = 0.7; //平衡因子 
    	
    	struct node
    	{
    		int son[2],val,siz,cnt,fa;
    		bool exist;
    	}t[MAXN];
    	
    	int newnode()
    	{
    		if(ncctot > 0) return ncc[ncctot--];
    		return ++tot;
    	}
    	int find(int x,int val)
    	{
    		if(t[x].val > val && t[x].son[0]) return find(t[x].son[0],val);
    		if(t[x].val < val && t[x].son[1]) return find(t[x].son[1],val);
    		return x;
    	}
    	void build(int x,int val,int fa)
    	{
    		t[x].son[0] = t[x].son[1] = 0;
    		t[x].fa = fa;
    		t[x].exist = 1;
    		t[x].val = val;
    		t[x].siz = t[x].cnt = 1;
    	}
    	void update(int x)
    	{
    		if(!x) return ;
    		t[x].siz = t[t[x].son[0]].siz + t[t[x].son[1]].siz + t[x].cnt;
    		update(t[x].fa);
    	}
    	void redfs(int x)
    	{
    		if(!x) return;
    		redfs(t[x].son[0]);
    		if(t[x].exist) re[++retot][0] = t[x].val,re[retot][1] = t[x].cnt;
    		ncc[++ncctot] = x;
    		redfs(t[x].son[1]);
    	}
    	int renow(int l,int r,int fa)
    	{
    		if(l > r) return 0;
    		int ID = newnode(),mid = (l+r) >> 1;
    		t[ID].val = re[mid][0];
    		t[ID].cnt = re[mid][1];
    		t[ID].fa = fa;
    		t[ID].son[0] = renow(l,mid-1,ID);
    		t[ID].son[1] = renow(mid+1,r,ID);
    		t[ID].siz = t[t[ID].son[0]].siz + t[t[ID].son[1]].siz + t[ID].cnt;
    		t[ID].exist = 1;
    		return ID; 
    	}
    	void rebuild(int x)
    	{
    		retot = 0;
    		redfs(x);
    		if(x == rt) rt = renow(1,retot,0);
    		else
    		{
    			if(t[t[x].fa].son[0] == x) t[t[x].fa].son[0] = renow(1,retot,t[x].fa);
    			else t[t[x].fa].son[1] = renow(1,retot,t[x].fa);
    			update(t[x].fa);
    		}
    	}
    	void find_rebuild(int x,int val)
    	{
    		if(!x) return;
    		if(1.0 * Max(t[t[x].son[0]].siz,t[t[x].son[1]].siz) > t[x].siz * alpha) {rebuild(x);return;}
    		if(t[x].val != val) find_rebuild(t[x].son[val > t[x].val],val);
    	}
    	void ins(int val)
    	{
    		if(!rt)
    		{
    			build(rt = newnode(),val,0);
    			return;
    		}
    		int dz = find(rt,val);
    		if(val == t[dz].val)
    		{
    			t[dz].cnt++;
    			t[dz].exist = 1;
    			update(dz);
    		}
    		else
    		{
    			if(val < t[dz].val) t[dz].son[0] = newnode(),build(t[dz].son[0],val,dz),update(t[dz].son[0]);
    			else t[dz].son[1] = newnode(),build(t[dz].son[1],val,dz),update(t[dz].son[1]);
    		}
    		find_rebuild(rt,val);
    	}
    	void del(int val)
    	{
    		int dz = find(rt,val);
    		if(t[dz].val == val) 
    		{
    			t[dz].cnt --;
    			if(!t[dz].cnt) t[dz].exist = 0;
    			update(dz);
    			find_rebuild(rt,val);
    		}
    	}
    	int rk(int val)
    	{
    		int now = rt,ret = 0;
    		while(t[now].val != val && now)
    		{
    			if(t[now].val < val) ret += t[now].cnt + t[t[now].son[0]].siz,now = t[now].son[1];
    			else now = t[now].son[0];
    		}
    		ret += t[t[now].son[0]].siz;
    		return ret + 1;
    	}
    	int findrk(int x) 
    	{
    		int now = rt;
    		while(1)
    		{
    			if(t[t[now].son[0]].siz >= x) now = t[now].son[0];
    			else if(t[t[now].son[0]].siz + t[now].cnt < x) x -= t[t[now].son[0]].siz + t[now].cnt,now = t[now].son[1];
    			else return t[now].val;
    		}
    	}
    	int pre(int val)
    	{
    		return findrk(rk(val)-1);
    	} 
    	int suc(int val)
    	{
    		return findrk(rk(val+1));
    	}
    	void debug(int x)
    	{
    		if(!x) return;
    		debug(t[x].son[0]);
    		if(t[x].exist)
    			Put(x,' '),Put(t[x].val,'
    ');
    		debug(t[x].son[1]);
    //		update(x);
    	}
    }s;
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	for(int T = Read(); T ;-- T)
    	{
    		int opt = Read(),x = Read();
    		if(opt == 1) s.ins(x);//插入x
    		else if(opt == 2) s.del(x);//删除x
    		else if(opt == 3) Put(s.rk(x),'
    ');//查询x的rank
    		else if(opt == 4) Put(s.findrk(x),'
    ');//查询rank为x的数 
    		else if(opt == 5) Put(s.pre(x),'
    ');//查询x的前缀 
    		else Put(s.suc(x),'
    ');//查询x的后缀 
    	}
    	return 0;
    }
    
  • 相关阅读:
    caffe常用层: batchNorm层和scale层
    简述configure、pkg-config、pkg_config_path三者的关系
    python删除list中元素的三种方法
    Leetcode 872. Leaf-Similar Trees
    Leetcode 508. Most Frequent Subtree Sum
    Leetcode 572. Subtree of Another Tree
    Leetcode 894. All Possible Full Binary Trees
    Leetcode 814. Binary Tree Pruning
    Leetcode 557. Reverse Words in a String III
    python 多维list声明时的小问题
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13392267.html
Copyright © 2011-2022 走看看