非旋Treap
Posted genius777
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了非旋Treap相关的知识,希望对你有一定的参考价值。
最近看到有一种不用旋转的treap,好像还可以持久化,于是就学了一下。
如果你还不会Treap的话,那你可以点击这里,对旋转Treap有个大致了解,这里就不赘述Treap的性质了。
treap就是tree+heap。它的每个节点的权值data满足排序二叉树的性质,随机权值key满足堆的性质。由于key是随机的所以它大致是平衡的。
不基于旋转的treap有两个基本操作:
merge(a,b):返回一个treap,包含a,b两个treap中的所有节点,但要保证b中所有节点权值都大于等于a。
split(a,n)返回两个treap l,r。其中l中包含treap a中的前n个节点,r中包含treap a中的剩余节点。
这两个操作的实现都很简单(这里我们维护小根堆的性质):
merge(a,b):若a的key< b的key则将a的右儿子变为merge(a的右儿子,b)。
否则将b的左儿子变为merge(a,b的左儿子)。
split(a,n):若a左子树的size(记为m)=n则返回a的左子树,a和a的右子树。若m=n-1则返回a的左子树和a,a的右子树。否则若m>n则设{l,r}为split(a的左子树,n)将a的左子树设为r,返回l,a。若m< n-1则设{l,r}为split(a的右子树,n-m-1)将a的右儿子设为l,返回a,r。
有了这两操作我们就可以实现插入和删除了。
插入x:找到x所在位置,将其split开,在合并l,x与x,r。
删除x:找到x的位置,将x与其前后位置都split开,在合并另外两部份。
其余操作和不同平衡树一样。
【代码实现】
1 #include<cstdio> 2 #include<algorithm> 3 #define maxn 100010 4 #define mp make_pair 5 using namespace std; 6 typedef pair<int,int> pp; 7 struct node{ 8 int son[2],val,rd,size; 9 }t[maxn]; 10 int op,n,root,cnt; 11 const int INF=1e9+7; 12 void updata(int v){t[v].size=t[t[v].son[0]].size+t[t[v].son[1]].size+1;} 13 pp split(int v,int k) 14 { 15 if(k==0)return mp(0,v); 16 int ls=t[v].son[0],rs=t[v].son[1]; 17 if(t[ls].size==k) {t[v].son[0]=0,updata(v);return mp(ls,v);} 18 if(t[ls].size+1==k) {t[v].son[1]=0,updata(v);return mp(v,rs);} 19 if(t[ls].size>k) 20 { 21 pp tmp=split(ls,k); 22 t[v].son[0]=tmp.second,updata(v); 23 return mp(tmp.first,v); 24 } 25 pp tmp=split(rs,k-t[ls].size-1); 26 t[v].son[1]=tmp.first,updata(v); 27 return mp(v,tmp.second); 28 } 29 int merge(int x,int y) 30 { 31 if(!x||!y)return x+y; 32 if(t[x].rd<t[y].rd) {t[x].son[1]=merge(t[x].son[1],y),updata(x);return x;} 33 else {t[y].son[0]=merge(x,t[y].son[0]),updata(y);return y;} 34 } 35 int rank(int v,int k) 36 { 37 int ans=0,tmp=INF; 38 while(v) 39 { 40 if(k==t[v].val)tmp=min(tmp,ans+t[t[v].son[0]].size+1); 41 if(k>t[v].val)ans+=t[t[v].son[0]].size+1,v=t[v].son[1]; 42 else v=t[v].son[0]; 43 } 44 return tmp==INF?ans:tmp; 45 } 46 int find(int v,int k) 47 { 48 while(1) 49 { 50 if(t[t[v].son[0]].size+1==k)return t[v].val; 51 if(t[t[v].son[0]].size>=k)v=t[v].son[0]; 52 else k=k-t[t[v].son[0]].size-1,v=t[v].son[1]; 53 } 54 } 55 int pre(int v,int k) 56 { 57 int ans=-INF; 58 while(v) 59 { 60 if(t[v].val<k)ans=max(ans,t[v].val),v=t[v].son[1]; 61 else v=t[v].son[0]; 62 } 63 return ans; 64 } 65 int next(int v,int k) 66 { 67 int ans=INF; 68 while(v) 69 { 70 if(t[v].val>k)ans=min(ans,t[v].val),v=t[v].son[0]; 71 else v=t[v].son[1]; 72 } 73 return ans; 74 } 75 void insert(int v) 76 { 77 int k=rank(root,v); 78 pp tmp=split(root,k); 79 t[++cnt].val=v; 80 t[cnt].rd=rand(); 81 t[cnt].size=1; 82 root=merge(tmp.first,cnt); 83 root=merge(root,tmp.second); 84 } 85 void del(int v) 86 { 87 int k=rank(root,v); 88 pp tmp1=split(root,k); 89 pp tmp2=split(tmp1.first,k-1); 90 root=merge(tmp2.first,tmp1.second); 91 } 92 int main() 93 { 94 int x; 95 scanf("%d",&n); 96 for(int i=1;i<=n;i++) 97 { 98 scanf("%d%d",&op,&x); 99 if(op==1)insert(x); 100 else if(op==2)del(x); 101 else if(op==3)printf("%d ",rank(root,x)); 102 else if(op==4)printf("%d ",find(root,x)); 103 else if(op==5)printf("%d ",pre(root,x)); 104 else printf("%d ",next(root,x)); 105 } 106 return 0; 107 }
以上是关于非旋Treap的主要内容,如果未能解决你的问题,请参考以下文章