这是一篇低质量博客
但是笔者自己看效果可能很好(写给自己看的博客)
一、前言
失踪人口终于回归啦~
替罪羊树太简单了! 以致于板题调了两天呢!
二、讲解
我们已经学过很多平衡树了,对于平衡树满足的特点,我就不多赘述了
我们直接步入正题,讲解替罪羊树维持平衡的方法
首先我们要知道怎样才算不平衡,这样我们才好修复
直接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、其他操作
和其它的平衡树类似,不再展开
关于代码:笔者首次采用了内存池的打法,个人感觉这种写法很好,值得一学(你不学我也不拦着你)
三、练习
四、代码
板题代码
//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;
}