Treap基本用法总结

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

 

 

·树套树

i)三维偏序

树状数组套treap,树状数组每个点后都建一棵treap

洛谷P3810 (代码微丑,多多包涵 + 这是一周前写的,代码风格也略微不一样)

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

ii)二逼平衡树 bzoj3196

Description

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

Input

第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继

Output

对于操作1,2,4,5各输出一行,表示查询结果

Sample Input

9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

Sample Output

2
4
3
4
9

HINT

1.n和m的数据范围:n,m<=50000

2.序列中每个数的数据范围:[0,1e8]

3.虽然原题没有,但事实上5操作的k可能为负数
 
线段树+treap,同样每一个节点后建一棵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 = 50005;
 10 struct node{
 11     int v,rnd,size;
 12     node *pa,*ch[2];       
 13 }pool[20*N];
 14 int cnt,a[N];
 15  
 16 int rr=1;
 17 int Get_rnd(){
 18     rr=((((ll)rr*P2)%P1)*P1)%P2;
 19     return rr;
 20 }
 21  
 22 struct treap{
 23     node *root,*rf;
 24     int size(node *p){
 25         if(p) return p->size;
 26         return 0;    
 27     }
 28     void update(node *p){
 29         p->size=1+size(p->ch[0])+size(p->ch[1]);     
 30     }
 31     void rotate(node *p,int t){
 32         node *son=p->ch[!t],*pa=p->pa,*gp=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(pa==root) root=p;
 40         update(pa);update(p);     
 41     }
 42     void insert(node *p,node *nd){
 43         int f=0;
 44         if(nd->v>p->v) f=1;
 45         if(p->ch[f]==NULL){
 46             p->ch[f]=nd;
 47             nd->pa=p;
 48         }
 49         else insert(p->ch[f],nd);
 50         update(p);
 51         if(p->ch[f]->rnd>p->rnd) rotate(p->ch[f],f);
 52     }
 53     node *find(node *p,int k){
 54         if(p->v>k) return find(p->ch[1],k);
 55         else if(p->v==k) return p;
 56         else return find(p->ch[0],k);   
 57     }
 58     node *del(node *p,int v){/**/
 59         if(v==p->v){
 60             if(!p->ch[0] || !p->ch[1]){
 61                 int f=0;
 62                 if(p->ch[1]) f=1;
 63                 node *son=p->ch[f],*pa=p->pa;
 64                 pa->ch[p==pa->ch[1]]=son;
 65                 if(son) son->pa=pa;
 66                 if(root==p) root=son;
 67                 node *q=pa;
 68                 while(q!=NULL)
 69                     update(q),q=q->pa;
 70                 return p;
 71             }
 72             else {
 73                 int f=0;
 74                 if(p->ch[0]->rnd<p->ch[1]->rnd) f=1;
 75                 rotate(p->ch[f],f);
 76                 return del(p,v);
 77             }
 78         }
 79         else if(v<p->v) {
 80             node *q=del(p->ch[0],v);
 81             return q;
 82         }
 83         else {
 84             node *q=del(p->ch[1],v);
 85             return q;
 86         }
 87     }
 88     void remove(int x,int y){
 89         node *p=del(root,x);
 90         p->v=y;p->size=1;
 91         p->pa=NULL;p->ch[0]=NULL;p->ch[1]=NULL; 
 92         if(root) insert(root,p);/**/
 93         else{
 94             root=p;
 95             rf->ch[1]=root;
 96             root->pa=rf;     
 97         }
 98     }
 99     int rank(node *p,int v){
100         int ret=0;
101         if(p->v<v){
102             ret+=1+size(p->ch[0]);
103             if(p->ch[1]) ret+=rank(p->ch[1],v);            
104         } 
105         else if(p->ch[0]) ret+=rank(p->ch[0],v);
106         return ret;
107     }
108     int sub(node *p,int v){
109         int ret=2147483647;
110         if(p->v>v){
111             ret=min(ret,p->v);
112             if(p->ch[0]) ret=min(ret,sub(p->ch[0],v));           
113         }
114         else if(p->ch[1]) ret=min(ret,sub(p->ch[1],v));
115         return ret;
116     }
117     int pre(node *p,int v){
118         int ret=-2147483647;
119         if(p->v<v){
120             ret=max(ret,p->v);
121             if(p->ch[1]) ret=max(ret,pre(p->ch[1],v));           
122         }
123         else if(p->ch[0]) ret=max(ret,pre(p->ch[0],v));
124         return ret;
125     }
126     void inorder(node *p){
127         if(p->ch[0]) inorder(p->ch[0]);
128         printf("%d ",p->v);
129         if(p->ch[1]) inorder(p->ch[1]);     
130     }
131 };
132  
133 struct tree{
134     int l,r;
135     treap tr;
136     tree *left,*right;       
137 }pool2[N*4],*rt;
138 int cnt2;
139 void Build(tree *p,int l,int r){
140     p->l=l;p->r=r;
141     node *tmp=&pool[++cnt];p->tr.rf=tmp;
142     if(l==r) return;
143     int mid=(l+r)/2;
144     p->left=&pool2[++cnt2];p->right=&pool2[++cnt2];
145     Build(p->left,l,mid);
146     Build(p->right,mid+1,r);
147 }
148 int q_rank(tree *p,int l,int r,int x){
149     if(p->l==l && p->r==r){
150         return p->tr.rank(p->tr.root,x);
151     }
152     if(p->left->r>=r) return q_rank(p->left,l,r,x);
153     else if(p->right->l<=l) return q_rank(p->right,l,r,x);
154     else return q_rank(p->left,l,p->left->r,x)+q_rank(p->right,p->right->l,r,x);     
155 }
156 int q_pre(tree *p,int l,int r,int x){
157     if(p->l==l && p->r==r)
158         return p->tr.pre(p->tr.root,x);
159     if(p->left->r>=r) return q_pre(p->left,l,r,x);
160     else if(p->right->l<=l) return q_pre(p->right,l,r,x);
161     else return max(q_pre(p->left,l,p->left->r,x),q_pre(p->right,p->right->l,r,x));     
162 }
163 int q_sub(tree *p,int l,int r,int x){
164     if(p->l==l && p->r==r)
165         return p->tr.sub(p->tr.root,x);
166     if(p->left->r>=r) return q_sub(p->left,l,r,x);
167     else if(p->right->l<=l) return q_sub(p->right,l,r,x);
168     else return min(q_sub(p->left,l,p->left->r,x),q_sub(p->right,p->right->l,r,x));     
169 }
170 void add(tree *p,int l,int x){
171     node *tmp=&pool[++cnt];
172     tmp->v=x;tmp->size=1;tmp->rnd=Get_rnd(); 
173     if(p->tr.root!=NULL) p->tr.insert(p->tr.root,tmp);
174     else {
175         p->tr.root=tmp;
176         p->tr.rf->ch[1]=p->tr.root;
177         p->tr.root->pa=p->tr.rf;
178     }
179     if(p->l==l && p->r==l) return;
180     if(p->right->l<=l) add(p->right,l,x);
181     else add(p->left,l,x);    
182 }
183 void change(tree *p,int l,int x){
184     p->tr.remove(a[l],x);
185     if(p->l==l && p->r==l) return;
186     if(p->right->l<=l) change(p->right,l,x);
187     else change(p->left,l,x);
188 }
189  
190  
191 int main()
192 {
193     int n,m,i,opt,x,y,z,l,r,mid;
194     scanf("%d%d",&n,&m);
195     for(i=1;i<=n;i++) scanf("%d",&a[i]);
196      
197     //build
198     rt=&pool2[++cnt2];
199     Build(rt,1,n);
200     for(i=1;i<=n;i++)
201         add(rt,i,a[i]);
202      
203     while(m--){
204         scanf("%d",&opt);
205         if(opt==1){
206             scanf("%d%d%d",&x,&y,&z);
207             printf("%d\n",q_rank(rt,x,y,z)+1);           
208         }
209         else if(opt==2){
210             scanf("%d%d%d",&x,&y,&z);
211             l=0;r=1e8;     
212             while(l<r){
213                 mid=(l+r+1)/2;
214                 if(q_rank(rt,x,y,mid)+1<=z) l=mid;
215                 else r=mid-1;
216             }
217             printf("%d\n",l);
218         }
219         else if(opt==3){
220             scanf("%d%d",&x,&y);
221             change(rt,x,y);
222             a[x]=y;     
223         }
224         else if(opt==4){
225             scanf("%d%d%d",&x,&y,&z);
226             printf("%d\n",q_pre(rt,x,y,z));     
227         }
228         else{
229             scanf("%d%d%d",&x,&y,&z);
230             printf("%d\n",q_sub(rt,x,y,z));     
231         }
232     }
233      
234     return 0;    
235 }
View Code

 

 

 

posted @ 2017-11-25 21:54  秋千旁的蜂蝶~  阅读(1917)  评论(0编辑  收藏  举报