标签:dfs flat 第一个 scan string roo ble 过多 while
//平衡树 替罪羊树 //不进行旋转 当左右子树重量相差过大(通常以3:1为界)就把树拍扁重构 //重构即以最中心节点为根节点 二分建树 #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #define lim 0.75//拍扁重构的标准 using namespace std; int n,root,size,cnt; int goat,flat[1000001];//需要拍扁重构的节点,拍扁重构时暂存的数组 struct uio{ int son[2],val,siz,ava;//左右儿子,权值,子树大小+自己大小,未被删除的子树大小 bool exist;//标记是否被删除 }scg[1000001]; bool check(int now)//判断是否拍扁 { if((double)scg[now].ava*lim<=(double)max(scg[scg[now].son[0]].ava,scg[scg[now].son[1]].ava)) //这是说 如果此节点未被删除的节点总数的3/4比任意一棵子树未被删除的节点数少(即:一棵子树未被删除的节点数是另一棵的3倍还多) return true;//需要拍扁 return false;//不用拍扁 } void dfs(int now)//中序遍历,找出需要参与重构的节点 { if(!now) return; dfs(scg[now].son[0]); if(scg[now].exist) flat[++cnt]=now; dfs(scg[now].son[1]); } void build(int l,int r,int &now)//构造过程 { int mid=(l+r)/2; now=flat[mid]; if(l==r) { scg[now].son[0]=scg[now].son[1]=0; scg[now].siz=scg[now].ava=1; return; } if(l<mid) build(l,mid-1,scg[now].son[0]); else scg[now].son[0]=0; build(mid+1,r,scg[now].son[1]); scg[now].siz=scg[scg[now].son[0]].siz+scg[scg[now].son[1]].siz+1; scg[now].ava=scg[scg[now].son[0]].ava+scg[scg[now].son[1]].ava+1; } void rebuild(int &now)//重构 { cnt=0; dfs(now); if(cnt) build(1,cnt,now); else now=0; } int get_no(int k) { int now=root,ans=1; while(now) { if(scg[now].val>=k) now=scg[now].son[0]; else { ans+=scg[scg[now].son[0]].ava+scg[now].exist; now=scg[now].son[1]; } } return ans; } void insert(int &now,int k) { if(!now) { now=++size; scg[now].val=k; scg[now].siz=scg[now].ava=1; scg[now].exist=true; scg[now].son[0]=scg[now].son[1]=0; return; } scg[now].siz++; scg[now].ava++; if(scg[now].val>=k) insert(scg[now].son[0],k); else insert(scg[now].son[1],k); if(!check(now))//此节点不需要重构 {//注:此处大括号不可去除!!!否则100行else会对应92行if而不是90行if导致多次拍扁重构! if(goat)//子节点中有满足重构条件的点 { if(scg[now].son[0]==goat) rebuild(scg[now].son[0]); else rebuild(scg[now].son[1]); goat=0; } }//注:此处大括号不可去除!!!否则100行else会对应92行if而不是90行if导致多次拍扁重构! else goat=now;//此节点需要重构,则继续记录 } void del_pos(int &now,int k) { if(scg[now].exist&&scg[scg[now].son[0]].ava+1==k) { scg[now].exist=false; scg[now].ava--; return; } scg[now].ava--; if(scg[scg[now].son[0]].ava+scg[now].exist>=k) del_pos(scg[now].son[0],k); else del_pos(scg[now].son[1],k-scg[scg[now].son[0]].ava-scg[now].exist); } void del_val(int k) { del_pos(root,get_no(k)); if((double)scg[root].siz*lim>=scg[root].ava)//若根节点被删除的节点过多(即:超过总结点的1/4) rebuild(root);//重构根节点 } int get_num(int k) { int now=root; while(now) { if(scg[now].exist&&scg[scg[now].son[0]].ava+1==k) return scg[now].val; else if(scg[scg[now].son[0]].ava>=k) now=scg[now].son[0]; else { k-=scg[scg[now].son[0]].ava+scg[now].exist; now=scg[now].son[1]; } } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { int u,v; scanf("%d%d",&u,&v); if(u==1) insert(root,v); if(u==2) del_val(v); if(u==3) printf("%d\n",get_no(v)); if(u==4) printf("%d\n",get_num(v)); if(u==5) printf("%d\n",get_num(get_no(v)-1)); //前驱:即k的位置的前一位 if(u==6) printf("%d\n",get_num(get_no(v+1))); //后继:即比k大的第一个数的位置 不能直接加一是因为k可能不止一个 } return 0; }
标签:dfs flat 第一个 scan string roo ble 过多 while
原文地址:https://www.cnblogs.com/water-radish/p/9280885.html