// Update node info from its children.voidpush_up(intx){tot[x]=1+tot[lc[x]]+tot[rc[x]];sz[x]=cnt[x]+sz[lc[x]]+sz[rc[x]];}
应注意 tot[x] 和 sz[x] 的更新方式的不同。
重构操作
当树发生失衡时,需要对某个子树进行重构,使之尽可能平衡。重构分为两步:
对要重构的子树做中序遍历,将所有未删除节点存到序列中;
二分建树,即取中点为根,左右两侧递归地建子树,并更新节点信息。
参考实现如下:
参考实现
1 2 3 4 5 6 7 8 910111213141516171819202122232425
// Tree -> Array.voidflatten(intx){if(!x)return;flatten(lc[x]);if(cnt[x])tmp[n_tmp++]=x;flatten(rc[x]);}// Array -> Tree.intbuild(intll,intrr){if(ll>rr)return0;intmm=(ll+rr)/2;intx=tmp[mm];lc[x]=build(ll,mm-1);rc[x]=build(mm+1,rr);push_up(x);returnx;}// Rebuild a subtree.voidrebuild(int&x){n_tmp=0;flatten(x);x=build(0,n_tmp-1);}
// Insert v into subtree of x.boolinsert(int&x,intv,intdep){boolcheck=false;if(!x){x=++id;val[x]=v;check=dep>std::log(tot[rt]+1)/std::log(1/ALPHA);}if(val[x]==v){if(!cnt[x])++tot_active;++cnt[x];}elseif(v<val[x]){check=insert(lc[x],v,dep+1);}else{check=insert(rc[x],v,dep+1);}push_up(x);if(check&&(tot[lc[x]]>ALPHA*tot[x]||tot[rc[x]]>ALPHA*tot[x])){rebuild(x);returnfalse;}returncheck;}// Insert v into the tree.voidinsert(intv){insert(rt,v,0);}
// Remove v from subtree of x.boolremove(intx,intv){if(!x)returnfalse;boolsucc=true;if(v<val[x]){succ=remove(lc[x],v);}elseif(v>val[x]){succ=remove(rc[x],v);}elseif(cnt[x]){--cnt[x];if(!cnt[x])--tot_active;}else{succ=false;}push_up(x);returnsucc;}// Remove v from the tree.boolremove(intv){boolsucc=remove(rt,v);if(!tot_active){rt=0;}elseif(succ&&tot_active<tot[rt]*ALPHA){rebuild(rt);}returnsucc;}
#include<cmath>#include<iostream>constexprintN=2e6;constexprdoubleALPHA=0.7;intid,rt,lc[N],rc[N],tot[N],tot_active;// Tree structure info.inttmp[N],n_tmp;// Space for rebuilding trees.intval[N],cnt[N],sz[N];// Node info.// Update node info from its children.voidpush_up(intx){tot[x]=1+tot[lc[x]]+tot[rc[x]];sz[x]=cnt[x]+sz[lc[x]]+sz[rc[x]];}// Tree -> Array.voidflatten(intx){if(!x)return;flatten(lc[x]);if(cnt[x])tmp[n_tmp++]=x;flatten(rc[x]);}// Array -> Tree.intbuild(intll,intrr){if(ll>rr)return0;intmm=(ll+rr)/2;intx=tmp[mm];lc[x]=build(ll,mm-1);rc[x]=build(mm+1,rr);push_up(x);returnx;}// Rebuild a subtree.voidrebuild(int&x){n_tmp=0;flatten(x);x=build(0,n_tmp-1);}// Insert v into subtree of x.boolinsert(int&x,intv,intdep){boolcheck=false;if(!x){x=++id;val[x]=v;check=dep>std::log(tot[rt]+1)/std::log(1/ALPHA);}if(val[x]==v){if(!cnt[x])++tot_active;++cnt[x];}elseif(v<val[x]){check=insert(lc[x],v,dep+1);}else{check=insert(rc[x],v,dep+1);}push_up(x);if(check&&(tot[lc[x]]>ALPHA*tot[x]||tot[rc[x]]>ALPHA*tot[x])){rebuild(x);returnfalse;}returncheck;}// Insert v into the tree.voidinsert(intv){insert(rt,v,0);}// Remove v from subtree of x.boolremove(intx,intv){if(!x)returnfalse;boolsucc=true;if(v<val[x]){succ=remove(lc[x],v);}elseif(v>val[x]){succ=remove(rc[x],v);}elseif(cnt[x]){--cnt[x];if(!cnt[x])--tot_active;}else{succ=false;}push_up(x);returnsucc;}// Remove v from the tree.boolremove(intv){boolsucc=remove(rt,v);if(!tot_active){rt=0;}elseif(succ&&tot_active<tot[rt]*ALPHA){rebuild(rt);}returnsucc;}// Find the rank of v, i.e., #{val < v} + 1.intfind_rank(intv){intres=0;intx=rt;while(x&&val[x]!=v){if(v<val[x]){x=lc[x];}else{res+=sz[lc[x]]+cnt[x];x=rc[x];}}returnres+sz[lc[x]]+1;}// Find the k-th smallest element.intfind_kth(intk){if(k<=0||sz[rt]<k)return-1;intx=rt;for(;;){if(k<=sz[lc[x]]){x=lc[x];}elseif(k<=sz[lc[x]]+cnt[x]){returnval[x];}else{k-=sz[lc[x]]+cnt[x];x=rc[x];}}return-1;}// Find predecessor.intfind_prev(intx){returnfind_kth(find_rank(x)-1);}// Find successor.intfind_next(intx){returnfind_kth(find_rank(x+1));}intmain(){intn;std::cin>>n;for(;n;--n){intop,x;std::cin>>op>>x;switch(op){case1:insert(x);break;case2:remove(x);break;case3:std::cout<<find_rank(x)<<'\n';break;case4:std::cout<<find_kth(x)<<'\n';break;case5:std::cout<<find_prev(x)<<'\n';break;case6:std::cout<<find_next(x)<<'\n';break;}}return0;}
参考资料
Galperin, Igal, and Ronald L. Rivest. "Scapegoat trees." Proceedings of the fourth annual ACM-SIAM Symposium on Discrete algorithms. 1993.