Treap=Tree+Heap  起名的人非常有才

 

Treap是啥?

一棵二叉搜索树可能退化成链,那样各种操作的效率都比较低

于是可爱的Treap在每个节点原先值v的基础上加了一个随机数rnd,树的形态要满足是rnd的大根堆或小根堆

可以说是普通BST的进化版吧。

Q:为什么rnd要满足是大根堆或小根堆,不能是二叉搜索树吗?

A:不能!二叉搜索树旋转时一直满足是二叉搜索树,也就是说值与值之间的相对顺序不管怎么转都是一定的。Treap本身就是二叉搜索树,在每插入一个新节点时,该节点在二叉搜索树中的相对位置是一定的。根据v而插入的位置,若此时rnd不满足二叉搜索树,那怎么旋转都无法满足是rnd的二叉搜索树。

Q:那为什么rnd可满足大根堆或小根堆呢?

A:以大根堆为例。用类似循环不定式证明。

i)假设在插入一个点前树的形态已满足是rnd的大根堆。按照v先将这个点p插到treap中,如果v比其父节点pa的rnd值大,就把p旋转到pa的位置。pa旋到下面后,连上了p的一个子节点son。因为原来rnd满足大根堆,那么pa的rnd一定大于son的rnd,此时p及其子树满足是rnd的大根堆。以此类推不断把p向上旋转,直到p的rnd小于pa的rnd。此时整棵树满足是rnd的大根堆,也就满足treap的要求

ii)当只有一个节点时,显然满足treap要求

 

Treap基本操作

维护一个有序序列,支持插入、删除,询问前驱后继、排名,区间加减等

Treap V.S. Splay

不像splay用起来那样方便,也没有splay像reverse之类的操作,但是比较好写,常数也稍微小一点

Treap V.S. 红黑树

跟红黑树相比,红黑树的效率更稳定(毕竟Treap有随机数),但红黑树写起来太过复杂。

用STL的set很方便,但不能查排名等信息

 

模板(洛谷P3369)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #define INF 100000007
  5 #define P1 39916801
  6 #define P2 4987657
  7 using namespace std;
  8 
  9 typedef long long ll;
 10 const int N = 100005;
 11 struct node{
 12     int v,rnd,size;
 13     node *ch[2],*pa;       
 14 }pool[N];
 15 int cnt;
 16 
 17 int rr;
 18 int Getrnd(){  //生成随机数
 19     rr=((ll)rr*P1)%P2;
 20     return rr;    
 21 }
 22 
 23 struct treap{
 24     node *root,*rf;
 25     int size(node *p){
 26         return p?p->size:0;    
 27     }
 28     void update(node *p){
 29         p->size=size(p->ch[0])+size(p->ch[1])+1;     
 30     }
 31     void rotate(node *p,int t){
 32         node *son=p->ch[!t],*pa=p->pa,*gp=p->pa->pa;
 33         pa->ch[t]=son;
 34         if(son) son->pa=pa;
 35         p->ch[!t]=pa;
 36         pa->pa=p;
 37         p->pa=gp;
 38         gp->ch[pa==gp->ch[1]]=p;
 39         if(root==pa) root=p;
 40         update(pa);update(p); 
 41     }
 42     void insert(node *p,node *nd){
 43         int f=p->v<nd->v?1:0;
 44         if(!p->ch[f]){
 45             p->ch[f]=nd;
 46             nd->pa=p;              
 47         }
 48         else insert(p->ch[f],nd);
 49         update(p);
 50         if(p->ch[f]->rnd>p->rnd) rotate(p->ch[f],f);
 51     }
 52     void Ins(int v){
 53         node *nd=&pool[++cnt];
 54         nd->v=v;nd->size=1;nd->rnd=Getrnd();
 55         nd->pa=nd->ch[0]=nd->ch[1]=NULL;
 56         if(root) insert(root,nd);
 57         else{
 58             root=nd;
 59             root->pa=rf;
 60             rf->ch[1]=root;
 61         }
 62     }
 63     void del(node *p,int v){ //删除 注意向上更新处容易写错
 64         if(p->v==v){
 65             if(!p->ch[0] || !p->ch[1]){
 66                 node *pa=p->pa,*son=p->ch[p->ch[0]?0:1];
 67                 pa->ch[p==pa->ch[1]]=son;
 68                 if(son) son->pa=pa;
 69                 if(p==root) root=son;
 70                 while(pa)
 71                     update(pa),pa=pa->pa;
 72             }
 73             else{
 74                 int f=p->ch[1]->rnd>p->ch[0]->rnd?1:0;
 75                 rotate(p->ch[f],f);del(p,v);
 76             }
 77         }
 78         else del(p->ch[v>p->v],v);
 79     }
 80     int rank(node *p,int v){ //比v小的节点个数
 81         if(!p) return 0;
 82         if(p->v<v) return 1+size(p->ch[0])+rank(p->ch[1],v);
 83         else return rank(p->ch[0],v);
 84     }
 85     int find(node *p,int k){ //询问排名第k的节点值
 86         if(size(p->ch[0])>=k) return find(p->ch[0],k);
 87         if(size(p->ch[0])==k-1) return p->v;
 88         return find(p->ch[1],k-size(p->ch[0])-1);
 89     }
 90     int pre(node *p,int v){//前驱
 91         if(!p) return -INF;
 92         if(v>p->v) return max(p->v,pre(p->ch[1],v));
 93         else return pre(p->ch[0],v);
 94     }
 95     int sub(node *p,int v){//后继
 96         if(!p) return INF;
 97         if(v<p->v) return min(p->v,sub(p->ch[0],v));
 98         else return sub(p->ch[1],v);
 99     }
100     void inorder(node *p){
101         if(p->ch[0]) inorder(p->ch[0]);
102         printf("%d ",p->v);
103         if(p->ch[1]) inorder(p->ch[1]);     
104     }
105 }tr;
106 
107 int main()
108 {
109     int n,opt,x;
110     scanf("%d",&n);
111     
112     tr.rf=&pool[++cnt];
113     while(n--){
114         scanf("%d%d",&opt,&x);
115         switch(opt){
116             case 1:tr.Ins(x);break;//插入
117             case 2:tr.del(tr.root,x);break;//删除
118             case 3:printf("%d\n",tr.rank(tr.root,x)+1);break;//某数排名=比该数小的个数+1
119             case 4:printf("%d\n",tr.find(tr.root,x));break;//排名x的数
120             case 5:printf("%d\n",tr.pre(tr.root,x));break;//前驱
121             case 6:printf("%d\n",tr.sub(tr.root,x));break;//后继
122             default:break;
123         }
124     }
125     
126     return 0;
127 }

 

应用

·普通应用

i)bzoj3173 最长上升子序列

Description

给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?

Input

第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)

Output

N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。

Sample Input

3
0 0 2

Sample Output

1
1
2

HINT

100%的数据 n<=100000

 

代码:(这是几个月前写的,代码风格不太一样)

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<string.h>
  6 #define INF 2147483647
  7 using namespace std;
  8  
  9 const int MAXN=100005;
 10 struct node
 11 {
 12     int size,d,rnd;
 13     node *parent,*lson,*rson;
 14 }pool[MAXN],*root;
 15 int cnt,cnt1,n;
 16 int c[MAXN],dp[MAXN],ans[MAXN];
 17  
 18 void update(node *p)
 19 {
 20     p->size=1;
 21     if(p->lson) p->size+=p->lson->size;
 22     if(p->rson) p->size+=p->rson->size;     
 23 }
 24  
 25 void right_rotate(node *p)
 26 {
 27     node *lson=p->lson,*parent=p->parent,*gp=p->parent->parent;
 28     parent->rson=lson;
 29     if(lson) lson->parent=parent;
 30     p->lson=parent;parent->parent=p;
 31     p->parent=gp;
 32     if(gp)
 33     {
 34         if(parent==gp->lson) gp->lson=p;
 35         else gp->rson=p;
 36     }
 37     else root=p;
 38     update(parent);
 39     update(p);
 40 }
 41  
 42 void left_rotate(node *p)
 43 {
 44     node *rson=p->rson,*parent=p->parent,*gp=p->parent->parent;
 45     parent->lson=rson;
 46     if(rson) rson->parent=parent;
 47     p->rson=parent;parent->parent=p;
 48     p->parent=gp;
 49     if(gp)
 50     {
 51         if(parent==gp->lson) gp->lson=p;
 52         else gp->rson=p;
 53     }
 54     else root=p;
 55     update(parent);
 56     update(p);
 57 }
 58  
 59 int size(node *p)
 60 {
 61     if(p==NULL) return 0;
 62     return p->size;    
 63 }
 64  
 65 void insert(node *p,node *newnode,int rank)
 66 {
 67     if(size(p->lson)+1>=rank)
 68     {
 69         if(p->lson==NULL)
 70         {
 71             p->lson=newnode;
 72             newnode->parent=p;
 73             p->size++;
 74             return;                 
 75         }
 76         insert(p->lson,newnode,rank);
 77         p->size++;
 78         if(p->lson->rnd>p->rnd) left_rotate(p->lson);                        
 79     }
 80     else
 81     {
 82         if(p->rson==NULL)
 83         {
 84             p->rson=newnode;
 85             newnode->parent=p;
 86             p->size++;
 87             return;                 
 88         }
 89         insert(p->rson,newnode,rank-size(p->lson)-1);
 90         p->size++;
 91         if(p->rson->rnd>p->rnd) right_rotate(p->rson);    
 92     }
 93 }
 94  
 95 int main()
 96 {
 97     int i,a,j;
 98     node *tmp;
 99     scanf("%d",&n);
100     srand(1);
101     for(i=1;i<=n;i++)
102     {
103         scanf("%d",&a);
104         tmp=&pool[++cnt];
105         tmp->d=i;
106         srand(rand()%10007);
107         tmp->rnd=rand()%10007;
108         tmp->size=1;
109         if(i==1) root=tmp;
110         else insert(root,tmp,++a);
111     }
112      
113     cnt1=0;
114     memset(dp,127,sizeof(dp));
115     int len=0,t;
116     dp[0]=-INF;
117     for(i=1;i<=n;i++)
118     {
119         t=upper_bound(dp,dp+len+1,c[i])-dp;
120         if(dp[t-1]<=c[i])
121         {
122             dp[t]=min(dp[t],c[i]);
123             ans[c[i]]=t;
124             len=max(len,t);
125         }            
126     }
127      
128     ans[0]=0;
129     for(i=1;i<=n;i++)
130     {
131         ans[i]=max(ans[i],ans[i-1]);
132         printf("%d\n",ans[i]);                 
133     }
134      
135     return 0;    
136 }
View Code

 

ii) noip2017提高day2-3 列队

(洛谷P3960)

n行以及最后一列各维护一个treap(这样共n+1个),反着来考虑,把每次出队的人加会队列

需要注意的是每行最后一列的要加到第n+1个treap中

细节还挺多的,要想清楚

代码:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #define P1 39916801
  5 #define P2 4987657
  6 using namespace std;
  7 
  8 typedef long long ll;
  9 const int N = 300005;
 10 
 11 int rr=1;
 12 int Get_rnd(){
 13     rr=((ll)rr*P2)%P1;
 14     return rr;
 15 }
 16 
 17 struct node{
 18     int v,rnd,id,lazy,size;
 19     node *pa,*ch[2];       
 20 }pool[4*N],*tmp,*num[N];
 21 int cnt;
 22 
 23 struct treap{
 24     node *root,*rf;
 25     int size(node *p){
 26         if(p) return p->size;
 27         return 0;    
 28     }
 29     void update(node *p){
 30         p->size=1+size(p->ch[0])+size(p->ch[1]);     
 31     }
 32     void pushdown(node *p){
 33         if(p->lazy){
 34             p->v+=p->lazy;
 35             if(p->ch[0]) p->ch[0]->lazy+=p->lazy;
 36             if(p->ch[1]) p->ch[1]->lazy+=p->lazy;
 37             p->lazy=0;           
 38         }
 39     }
 40     void rotate(node *p,int t){
 41         node *son=p->ch[!t],*pa=p->pa,*gp=p->pa->pa;
 42         pa->ch[t]=son;
 43         if(son) son->pa=pa;
 44         pa->pa=p;
 45         p->ch[!t]=pa;
 46         p->pa=gp;
 47         gp->ch[pa==gp->ch[1]]=p;
 48         if(pa==root) root=p;
 49         update(pa);update(p);
 50     }
 51     void insert(node *p,node *nd,int t){
 52         pushdown(p);
 53         int f=0;
 54         if(nd->v>p->v) f=1;
 55         if(p->ch[f]==NULL){
 56             p->ch[f]=nd;
 57             nd->pa=p;
 58             nd->size=1;nd->lazy=0;
 59         }
 60         else insert(p->ch[f],nd,t);
 61         update(p);
 62         if(f==0 && t==0){
 63             p->v++;
 64             if(p->ch[1]) p->ch[1]->lazy++;         
 65         }
 66         if(p->ch[f]->rnd>p->rnd) rotate(p->ch[f],f);
 67     }
 68     void Ins(node *nd,int t){
 69         if(root==NULL){
 70             root=nd;
 71             root->pa=rf;
 72             rf->ch[1]=root;               
 73         }     
 74         else insert(root,nd,t);
 75     }
 76     void add(node *p,int v){
 77         pushdown(p);
 78         if(p->v>=v) {
 79             p->v++;
 80             if(p->ch[1]) p->ch[1]->lazy++;
 81             if(p->ch[0]) add(p->ch[0],v);         
 82         }
 83         else if(p->ch[1]) add(p->ch[1],v);
 84     }
 85     void del(node *p){
 86         pushdown(p);
 87         if(p->ch[1]) del(p->ch[1]);
 88         else{
 89             node *son=p->ch[0],*pa=p->pa;
 90             pa->ch[1]=son;/**/
 91             if(son) son->pa=pa;
 92             if(root==p) root=son;     
 93         }
 94         update(p);
 95     }
 96     node *last(node *p){
 97         pushdown(p);
 98         if(p->ch[1]) return last(p->ch[1]);
 99         return p;    
100     }
101     void update_all(node *p){
102         pushdown(p);
103         if(p->ch[0]) update_all(p->ch[0]);
104         if(p->ch[1]) update_all(p->ch[1]);     
105     }
106     void inorder(node *p){
107         pushdown(p);
108         if(p->ch[0]) inorder(p->ch[0]);
109         printf("%d ",p->v);
110         if(p->ch[1]) inorder(p->ch[1]);     
111     }
112 }tr[N];
113 
114 int n,m,Q;
115 int xx[N],yy[N];
116 
117 int main()
118 {
119     int i,j;
120     scanf("%d%d%d",&n,&m,&Q);
121     for(i=1;i<=Q;i++)
122         scanf("%d%d",&xx[i],&yy[i]);
123         
124     for(i=1;i<=n+1;i++)
125         tr[i].rf=&pool[++cnt];
126         
127     for(i=Q;i>0;i--){
128         if(tr[n+1].root && tr[n+1].last(tr[n+1].root)->v==n){
129             tmp=tr[n+1].last(tr[n+1].root);
130             tr[n+1].del(tr[n+1].root);
131         }
132         else tmp=&pool[++cnt];
133         
134         tmp->v=yy[i];tmp->id=xx[i];
135         tmp->size=1;tmp->lazy=0;
136         tmp->ch[0]=tmp->ch[1]=tmp->pa=NULL;
137         tmp->rnd=Get_rnd();
138         tr[xx[i]].Ins(tmp,0);
139         
140         num[i]=tmp;
141         if(tr[n+1].root) tr[n+1].add(tr[n+1].root,xx[i]);
142         
143         tmp=tr[xx[i]].last(tr[xx[i]].root);
144         if(tmp->v==m){
145             tr[xx[i]].del(tr[xx[i]].root);
146             tmp->v=xx[i];tmp->id=n+1;
147             tmp->size=1;tmp->lazy=0;
148             tmp->ch[0]=tmp->ch[1]=tmp->pa=NULL;
149             tmp->rnd=Get_rnd();
150             tr[n+1].Ins(tmp,1);          
151         }
152     }
153     
154     ll ret=0;
155     for(i=1;i<=n+1;i++)
156         if(tr[i].root) tr[i].update_all(tr[i].root);
157     for(i=1;i<=Q;i++){
158         ret=0;
159         if(num[i]->id==n+1)
160             ret=(ll)num[i]->v*m;
161         else
162             ret=((ll)num[i]->id-1)*m+num[i]->v;
163         printf("%lld\n",ret);/**/
164     }
165     
166     return 0;    
167 }
View Code

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-08-15
  • 2021-07-23
  • 2021-12-21
猜你喜欢
  • 2022-12-23
  • 2022-01-28
  • 2021-05-27
  • 2021-05-25
  • 2021-05-12
  • 2021-07-30
  • 2022-02-19
相关资源
相似解决方案