zoukankan      html  css  js  c++  java
  • 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
    ",tr.rank(tr.root,x)+1);break;//某数排名=比该数小的个数+1
    119             case 4:printf("%d
    ",tr.find(tr.root,x));break;//排名x的数
    120             case 5:printf("%d
    ",tr.pre(tr.root,x));break;//前驱
    121             case 6:printf("%d
    ",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
    ",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
    ",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
    ",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
    ",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
    ",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
    ",q_pre(rt,x,y,z));     
    227         }
    228         else{
    229             scanf("%d%d%d",&x,&y,&z);
    230             printf("%d
    ",q_sub(rt,x,y,z));     
    231         }
    232     }
    233      
    234     return 0;    
    235 }
    View Code
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    修复PLSQL Developer 与 Office 2010的集成导出Excel 功能
    Using svn in CLI with Batch
    mysql 备份数据库 mysqldump
    Red Hat 5.8 CentOS 6.5 共用 输入法
    HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver
    变更RHEL(Red Hat Enterprise Linux 5.8)更新源使之自动更新
    RedHat 5.6 问题简记
    Weblogic 9.2和10.3 改密码 一站完成
    ExtJS Tab里放Grid高度自适应问题,官方Perfect方案。
    文件和目录之utime函数
  • 原文地址:https://www.cnblogs.com/lindalee/p/7896594.html
Copyright © 2011-2022 走看看