替罪羊树真的贼TM长。。。。
洛谷,普通平衡树
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<vector> using namespace std; const int maxn = 1e5+5; const double alpha = 0.75; struct node{ int l,r,val; int size,fact; ///子树大小,实际大小 bool exist; }tzy[maxn]; int cnt,root; ///新建节点 void newnode(int &now,int val) { now=++cnt; tzy[now].val=val; tzy[now].size=tzy[now].fact=1; tzy[now].exist=true; } ///判断是否平衡 bool imbalance(int now) { ///左右子树的size中最大的一个的大小大于节点大小*平衡因子 ///被删掉的节点个数大于0.3 if(max(tzy[tzy[now].l].size,tzy[tzy[now].r].size)>tzy[now].size*alpha || tzy[now].size-tzy[now].fact>tzy[now].size*0.3) return true; else return false; } vector<int>v; ///中序列遍历 void idr(int now) { if (!now)return; idr(tzy[now].l); if (tzy[now].exist) v.push_back(now); idr(tzy[now].r); } ///拎起来 void lift(int l,int r,int &now) { ///拎起来到叶子节点 if (l==r) { now=v[l]; ///变成叶子节点状态 tzy[now].l=tzy[now].r=0; tzy[now].size=tzy[now].fact=1; return; } int m=(l+r)>>1; ///防止值相同跑到左边去 while(m && l<m && tzy[v[m]].val==tzy[v[m-1]].val) m--; now=v[m]; if(l<m)lift(l,m-1,tzy[now].l); else tzy[now].l=0; ///向下取整,可以直接取 lift(m+1,r,tzy[now].r); tzy[now].size=tzy[tzy[now].l].size+tzy[tzy[now].r].size+1; tzy[now].fact=tzy[tzy[now].l].fact+tzy[tzy[now].r].fact+1; } void update(int now,int end) { if(!now)return; if (tzy[end].val<tzy[now].val) update(tzy[now].l,end); else update(tzy[now].r,end); tzy[now].size=tzy[tzy[now].l].size+tzy[tzy[now].r].size+1; } ///暴力重构 ///进行中序遍历拉成直线,挂起来,然后分治拎起来 void rebuild(int &now) { v.clear(); idr(now); if (v.empty()) { now=0; return; } lift(0,v.size()-1,now); } ///检查是否需要重构 ///不能从下往上找 ///重构条件----当前节点的左子树或者右子树的大小大于当前节点的大小乘以一个平衡因子alpha void check(int &now,int end) { if (now==end)return; ///判断当前节点是否平衡 if (imbalance(now)) { ///重构 rebuild(now); ///往上更新 update(root,now); return ; } ///终点在当前节点的左子树 if (tzy[end].val<tzy[now].val) check(tzy[now].l,end); else check(tzy[now].r,end); } ///插入操作 void ins(int &now,int val){ if (!now)//当前节点不存在 { newnode(now,val);; ///是否需要重构 check(root,now); return; } tzy[now].size++; tzy[now].fact++; ///小于左插,大于右插 if(val<tzy[now].val) ins(tzy[now].l,val); else ins(tzy[now].r,val); } ///惰性删除 void del(int now,int val) { ///当前节点存在,并且当前节点的值等于当前需要删除的值 if (tzy[now].exist && tzy[now].val==val) { tzy[now].exist=false; tzy[now].fact--; ///删除后是否平衡 check(root,now); return; } tzy[now].fact--; if (val<tzy[now].val) del(tzy[now].l,val); else del(tzy[now].r,val); } int getrank(int val) { int now=root,rank=1; while(now) { ///如果查找的值小于等于当前节点的值,往左找 if (val<=tzy[now].val) now=tzy[now].l; else { ///把左子树以及当前节点的值算进去 rank+=tzy[now].exist+tzy[tzy[now].l].fact; now=tzy[now].r; } // cout<<tzy[now].val<<" "<<rank<<endl; } // cout<<endl; return rank; } int getnum(int rank) { int now=root; while(now) { ///当前节点左子树+当前节点是否存在为rank,那么退出 if(tzy[now].exist && tzy[tzy[now].l].fact+tzy[now].exist==rank) break; else if(tzy[tzy[now].l].fact>=rank) now=tzy[now].l; else { rank-=tzy[tzy[now].l].fact+tzy[now].exist; now=tzy[now].r; } } return tzy[now].val; } int main(){ int t; int op,x; scanf("%d",&t); cnt=0; while(t--){ scanf("%d%d",&op,&x); if (op==1){ ins(root,x); }else if (op==2){ del(root,x); }else if (op==3){ printf("%d ",getrank(x)); }else if (op==4){ printf("%d ",getnum(x)); }else if (op==5){ ///查询的是x的排名-1的数是什么 printf("%d ",getnum(getrank(x)-1)); }else { ///查询的是小于等于x+1的数的个数 ///因为我们在查找的时候强行把这个值rank值自动设置为1 ///那么就强行认为这个数是rank1,然后查询比这个数小的个数 printf("%d ",getnum(getrank(x+1))); } } return 0; } /* 5 1 2 1 4 1 6 6 4 */