|
沙发
楼主 |
发表于 2020-3-22 18:55:36
|
只看该作者
训练简单平衡树的好题,可以用多种树结构做,我先做了有个替罪羊树:
- #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--; ///次数>1
- 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;
- }
复制代码 |
|