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
    既然选择了远方,便只顾风雨兼程
  • 相关阅读:
    Win7下搭建svn服务与客户端的使用
    八皇后问题
    python开发常见应用第一卷(OS遍历文件并存储文件路径到数据库)
    python3下scrapy爬虫(第十四卷:scrapy+scrapy_redis+scrapyd打造分布式爬虫之执行)
    python3下scrapy爬虫(第十三卷:scrapy+scrapy_redis+scrapyd打造分布式爬虫之配置)
    网站爬取-案例四:知乎抓取(COOKIE登录抓取个人中心)(第二卷)
    网站爬取-案例四:知乎抓取(COOKIE登录抓取个人中心)(第一卷)
    网站爬取-案例三:今日头条抓取(ajax抓取JS数据)
    网站爬取-案例二:天猫爬取( 第一卷:首页数据抓取)
    网站爬取-案例一:猫眼电影TOP100
  • 原文地址:https://www.cnblogs.com/lindalee/p/7896594.html
Copyright © 2011-2022 走看看