数据结构入门1—Treap

来源:互联网 发布:余姚数控编程培训 编辑:程序博客网 时间:2024/06/07 20:49

debug3个月把洛谷刷屏,终于过了。。。。(一开始写了两百行,后来看了大孙代码才搞点小技巧改短了些)

treap,树堆,是指有一个随机附加域满足堆的性质的二叉搜索树,其结构相当于以随机数据插入的二叉搜索树。其基本操作的期望时间复杂度为O(logn)。相对于其他的平衡二叉搜索树,Treap的特点是实现简单,且能基本实现随机平衡的结构。我们可以看到,如果一个二叉排序树节点插入的顺序是随机的,这样我们得到的二叉排序树大多数情况下是平衡的,即使存在一些极端情况,但是这种情况发生的概率很小,所以我们可以这样建立一颗二叉排序树,而不必要像AVL那样旋转,可以证明随机顺序建立的二叉排序树在期望高度是O(logn),但是某些时候我们并不能得知所有的带插入节点,打乱以后再插入。所以我们需要一种规则来实现这种想法,并且不必要所有节点。也就是说节点是顺序输入的,我们实现这一点可以用Treap。Treap=Tree+Heap。

Treap是一棵二叉排序树,它的左子树和右子树分别是一个Treap,和一般的二叉排序树不同的是,Treap纪录一个额外的数据,就是优先级。Treap在以关键码构成二叉排序树的同时,还满足堆的性质(在这里我们假设节点的优先级大于该节点的孩子的优先级)。但是这里要注意的是Treap和二叉堆有一点不同,就是二叉堆必须是完全二叉树,而Treap可以并不一定是。

以上来自百度百科。

简而言之,treap中序遍历就是原数组排好序后的排列,其中随机出来的优先级满足堆的性质。

与Splay不同之处是Splay的中序遍历就是原数组的排列顺序,而且与Splay的旋转操作等不同。treap比Splay好写(然而。。。)

新手很容易忽略的细节问题是一个数可能会添加多次,需要存一下每个数有多少个,每次查询和修改不要忘了它。

Treap模板题(洛谷)

//Serene#include<algorithm>#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<cmath>#include<ctime>using namespace std;const int maxn=100000+10;int n,tot=0,ans1,ans2,root;int aa,ff;char cc;int read() {aa=0;ff=1;cc=getchar();while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();if(cc=='-') ff=-1,cc=getchar();while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();return aa*ff;}struct Node{int num,rnd,son[2],sum,x;}node[maxn];void rotate(int &pos,int p) {int s=node[pos].son[p];node[s].sum=node[pos].sum;node[pos].son[p]=node[s].son[!p];node[s].son[!p]=pos;node[pos].sum=node[pos].x+node[node[pos].son[0]].sum+node[node[pos].son[1]].sum;pos=s;}void add(int &pos,int x) {if(!pos) {pos=++tot;node[pos].num=x;node[pos].rnd=rand();node[pos].sum=node[pos].x=1;return ;}node[pos].sum++;if(node[pos].num==x) {node[pos].x++; return;}int p=x>node[pos].num;add(node[pos].son[p],x);if(node[node[pos].son[p]].rnd<node[pos].rnd) rotate(pos,p);}void del(int &pos,int x) {if(!pos) return;if(node[pos].num==x) {if(node[pos].x>1) {node[pos].x--;node[pos].sum--;return;}if(node[pos].son[0]*node[pos].son[1]==0) {pos=node[pos].son[0]+node[pos].son[1]; return;}int p= node[node[pos].son[1]].rnd<node[node[pos].son[0]].rnd;rotate(pos,p);node[pos].sum--;del(node[pos].son[!p],x);}else {node[pos].sum--;if(node[pos].num>x) del(node[pos].son[0],x);else del(node[pos].son[1],x);}}int qrank(int pos,int x) {if(node[pos].num==x) return node[node[pos].son[0]].sum+1;if(node[pos].num>x) return qrank(node[pos].son[0],x);return node[node[pos].son[0]].sum+node[pos].x+qrank(node[pos].son[1],x);}int qnum(int pos,int x) {if(x>node[node[pos].son[0]].sum&&x<=node[node[pos].son[0]].sum+node[pos].x) return node[pos].num;if(x<=node[node[pos].son[0]].sum) return qnum(node[pos].son[0],x);return qnum(node[pos].son[1],x-node[pos].x-node[node[pos].son[0]].sum);}void q1(int pos,int x) {if(!pos) return;if(x>node[pos].num) {ans1=node[pos].num;q1(node[pos].son[1],x);}else q1(node[pos].son[0],x);}void q2(int pos,int x) {if(!pos) return;if(x<node[pos].num) {ans2=node[pos].num;q2(node[pos].son[0],x);}else q2(node[pos].son[1],x);}int main() {srand((unsigned)time(NULL));n=read();int opt,x,y;for(int i=1;i<=n;++i) {opt=read();x=read();if(opt==1) add(root,x);else if(opt==2) del(root,x);else if(opt==3) printf("%d\n",qrank(root,x));else if(opt==4) printf("%d\n",qnum(root,x));else if(opt==5) q1(root,x),printf("%d\n",ans1);else q2(root,x),printf("%d\n",ans2);}return 0;}


原创粉丝点击