华师一附中OI组
标题:
替罪羊树
[打印本页]
作者:
admin
时间:
2020-3-22 20:10
标题:
替罪羊树
基本思路,不平衡的就把他打扁,然后重建。什么叫做不平衡呢?我们定义左儿子的节点数和右儿子的节点数差距较大就为不平衡,完美的平衡是左右儿子数量相等,左右儿子各占根总数的50%。但这个很难,一般定义左右儿子中某个数量超过根节点的alpha=75%为不平衡,需要重构。若alpha太大,>80%,重构次数太多,费时,太小<70%,树就不太平衡,影响以后查找和删除的效果。
如何重构呢?暴力点,先把这个子树拍平,中序遍历到一个数组,然后从中间开始二分类似线段树完美建树。
所以在一般的BST基础上,除了ls rs val cnt等之外还需要加上sz记录我这棵树下所有节点的数目。
struct node
{
int val,cnt;
int ls,rs,sz; ///lsrs左右儿子 sz本子树下所有节点个数
} a[N];
复制代码
重建过程
void RB(int &rt) ///重建rt
{
if(rt==0) return;
float t=a[rt].sz*p; ///左右儿子不能大于rt的0.75
bool b1=a[a[rt].ls].sz>t;
bool b2=a[a[rt].rs].sz>t;
if( b1|| b2)
{
ita=0;
Inorder(rt);
rt=build(1,ita);
}
}
复制代码
拍扁的过程,其实就是递归中序遍历,不过是输出到临时数组
void Inorder(int rt) //倒到数组
{
if(rt>0)
{
Inorder(a[rt].ls);
ta[++ita]=rt;
Inorder(a[rt].rs);
}
}
复制代码
重新完美建树的过程,完全类似线段树
int build(int l, int r) //l-r重新建树
{
if(l>r) return 0;
int m=(l+r)/2;
a[ta[m]].ls=build(l,m-1);
a[ta[m]].rs=build(m+1,r);
pushup(ta[m]);
return ta[m];
}
复制代码
作者:
admin
时间:
2020-3-22 20:10
#include<bits/stdc++.h>
using namespace std;
const int N = 1001005;
const float p=0.75;
struct node
{
int val,cnt;
int ls,rs,sz; ///lsrs左右儿子 sz本子树下所有节点个数
} a[N];
int ta[N],ita;///转移数组
int n, tot, rt;
void ArrayPr()
{
for (int i=1; i<=tot; i++) cout<<setw(3)<<i;
cout<<endl;
for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].val;
cout<<endl;
for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].cnt;
cout<<endl;
for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].ls;
cout<<endl;
for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].rs;
cout<<endl;
for (int i=1; i<=tot; i++) cout<<setw(3)<<a[i].sz;
cout<<endl;
}
void BSTPr(int rt) ///中序输出以rt为根的BST
{
if (a[rt].ls>0) BSTPr(a[rt].ls);
cout<<a[rt].val<<' '; /// 也可以加上cnt
if (a[rt].rs>0) BSTPr(a[rt].rs);
}
void pushup(int rt)
{
int l=a[rt].ls, r=a[rt].rs;
a[rt].sz=a[l].sz+a[r].sz+a[rt].cnt;
}
int build(int l, int r)//l-r重新建树
{
if(l>r) return 0;
int m=(l+r)/2;
a[ta[m]].ls=build(l,m-1);
a[ta[m]].rs=build(m+1,r);
pushup(ta[m]);
return ta[m];
}
void Inorder(int rt)//倒到数组
{
if(rt>0)
{
Inorder(a[rt].ls);
ta[++ita]=rt;
Inorder(a[rt].rs);
}
}
void RB(int &rt) ///重建rt
{
if(rt==0) return;
float t=a[rt].sz*p; ///左右儿子不能大于rt的0,75
bool b1=a[a[rt].ls].sz>t;
bool b2=a[a[rt].rs].sz>t;
if( b1|| b2)
{
ita=0;
Inorder(rt);
rt=build(1,ita);
}
}
void Ins(int &rt, int x)
{
if(rt==0)
{
rt=++tot;
a[rt].val=x;
a[rt].sz=a[rt].cnt = 1;
}
else
{
RB(rt); /// 比原版多一句调整
if(a[rt].val==x) a[rt].cnt ++,a[rt].sz++;
else
{
if(a[rt].val<x) Ins(a[rt].rs, x);
else if(a[rt].val>x) Ins(a[rt].ls, x);
pushup(rt); /// 比原版多一句调整 线段树相似
}
}
}
int DelMin(int &rt) ///原版不变
{
int t;
if(a[rt].ls==0)///没有左儿子 那就是它
{
t=rt;
rt=a[rt].rs;
return t;
}
else
{
t=DelMin(a[rt].ls); ///递归
pushup(rt);///多了这个调整
return t;
}
}
void Del(int &rt,int x)
{
if (rt==0) return ;
else if(a[rt].val>x)
{
Del(a[rt].ls,x);
pushup(rt);
}
else if(a[rt].val<x)
{
Del(a[rt].rs,x);
pushup(rt);
}
else if(a[rt].val==x)
{
if(a[rt].cnt>1)a[rt].cnt--,a[rt].sz--;
else if(a[rt].ls==0)rt=a[rt].rs;
else if(a[rt].rs==0)rt=a[rt].ls;
else
{
int t=DelMin(a[rt].rs);
a[rt].val=a[t].val;
a[rt].cnt=a[t].cnt;
pushup(rt);
}
}
}
int Rank(int rt, int x) ///在RT子树中比x小的数 +1
{
if(a[rt].val==x) return a[a[rt].ls].sz+1; /// 找到了
if(a[rt].val<x) return a[a[rt].ls].sz +a[rt].cnt+ Rank(a[rt].rs,x);///左子树下面的都算
if(a[rt].val>x) return Rank(a[rt].ls,x);
}
int Getkth(int rt, int x) ///在RT子树中找第k小
{
int l=a[a[rt].ls].sz; /// RT的左儿子下的个数
if(l+1<=x && x<=l+a[rt].cnt) return a[rt].val;
if(l+1>x) return Getkth(a[rt].ls, x); ///左儿子里去找
if(l+a[rt].cnt<x) return Getkth(a[rt].rs, x-(l+a[rt].cnt));
}
int Pre(int rt, int x)
{
int p = rt, ans;
while(p>0)
{
if(x<=a[p].val) p=a[p].ls;
else
{
ans=p;
p=a[p].rs;
}
}
return ans;
}
int Suc(int rt, int x)
{
int p = rt, ans;
while(p>0)
{
if(a[p].val<=x) p=a[p].rs;
else
{
ans = p;
p=a[p].ls;
}
}
return ans;
}
int main()
{
cin>>n;
while(n--)
{
int opt, x;
cin>>opt>>x;
if(opt == 1) Ins(rt, x);
if(opt == 2) Del(rt, x);
if(opt == 3) cout<<Rank(rt, x)<<endl;
if(opt == 4) cout<<Getkth(rt, x)<<endl;
if(opt == 5) cout<<a[Pre(rt, x)].val<<endl;
if(opt == 6) cout<<a[Suc(rt, x)].val<<endl;
///ArrayPr();
///BSTPr(rt);
}
return 0;
}
复制代码
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2