zoukankan      html  css  js  c++  java
  • [模板]洛谷T3380 二逼平衡树 线段树套BST

    时隔一个月后,终于攻克了二分求K大的难题。。。特此纪念 2017.10.3

    好好的树套树模板题怎么没有一份线段树套平衡树的“标准”题解呢。。。虽然这方法比较low,但我还是来贴一发。。。

    据说这题常数巨大,若干份线段树套BST的代码都被卡常了

    萌新我看到这吓人的通过率不由瑟瑟发抖

    于是使出浑身解数,用了一大堆奇技淫巧进行疯狂的常数优化。。。

    然后。。。居然没被卡到。。。滑稽。。。

    进入正题:

    何为树套树?

    考虑这题要求的操作。区间操作要求使用线段树,求排名、K大什么的又要求使用BST,所以就可以祭出线段树套BST了,具体是指,在线段树划定的每个区间上都分别建立一棵BST。这样,空间复杂度就是线段树的宽×高,即为nlogn。

    这样操作,就将原先的一段区间分成了logn棵BST。对每个BST操作后,将结果合并即得答案。显然,这样一次操作的时间复杂度是log^2n。

    操作解析:

    每次操作先由线段树自顶向下查询,若当前线段树区间完全包含于待操作区间,则在本区间所属的BST内进行相应的平衡树操作并返回结果,全部操作结束后将所有结果合并即可。

    对于操作1:在每个BST内查询严格小于k的数的个数,将所有结果相加再加1即为答案。

    对于操作2:

    先吐槽一句。。。就是这个操作,折磨了我一个月之久。。。二分的细节什么的太恶心。。。

    对于树套树,这个操作貌似是无法直接实现的,因为区间并不是有序的QwQ

    那么要怎么搞呢?答案是二分,每次对二分出的值查询一次区间排名,不断逼近给定的k即可。

    但是,由于元素重复等等的原因,使得这个二分过程难以实现。。。

    这里对代码中的二分细节作一下解释:

    1.x的计算紧跟在l和r的变动之后,目的是使这三个值保持同步,保证结果准确;

    2.如果x的排名>k,联系求排名操作的性质,可推知这时的x一定大于结果,那么就将x以及比x大的值都排除,故有r=x-1。通过类似推理可得,当x的排名<=k时,须执行l=x;

    3.x的计算问题。

    如果写成x=(l+r)>>1,那么在某些情况下会死循环。原因如下:

    当l+1==r且对l查询满足其排名<=k时,按照(l+r)>>1计算的x等于l,那么会导致执行l=x,然而原本就有l==x。。。于是就死循环了~

    写成x=(l+r+1)>>1的作用是,让x偏向于r,这样,在发生上述情况时,会有如下变动:

    x=(l+r+1)>>1=r,当x的排名>k,那么执行r=x-1=l;当x的排名<=k,那么执行l=x=r。无论如何,都将得到l==r而退出循环,而不是死循环。

    如此便能解决问题。

    对于操作3:首先在原序列中找到pos位置原先的值,然后在每个BST中将该值删除再插入k即可。注意也要修改原序列中的值,以便下一次操作3时使用。

    对于操作4:在每个BST内求一次前驱,最后对所有结果取一次Max即可。

    对于操作5:与操作4同理。

    下面讲一下我的“奇技淫巧”。。。

    对于线段树套BST,因为线段树的结构稳定,所以BST就在很大程度上决定了代码的性能如何。

    那么选择怎样的BST呢?每次都进行暴力单点插入?不行不行,会被卡常。。。

    NOI2005 维护数列 这道题告诉我,建立完全平衡的BST,其性能远优于上面的方法。这样做,不仅建树速度快,而且对于提升后续操作的性能效果明显。

    但是,建立完全平衡的BST,需要序列有序,然而这里的序列是无序的。

    每次都排序一下?不行不行,时间更会炸掉。。。

    这时我想,能不能让当前排序后的序列,方便上层序列的排序,从而减少时间消耗呢?

    突然我回想起归并排序的性质。。。没错!对于建树的过程,整体嵌入一个归并,便可达到目的,建立起完全平衡的BST。

    奇技淫巧”细节详见代码。

    代码如下:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<ctime>
      6 #include<cstdlib>
      7 
      8 #include<string>
      9 #include<stack>
     10 #include<queue>
     11 #include<vector>
     12 #include<algorithm>
     13 #include<map>
     14 #include<set>
     15 
     16 #define inf 2147483647
     17 
     18 using namespace std;
     19 
     20 inline void read(int &x){  //读入优化 
     21     x=0;
     22     char t=getchar();
     23     bool f=0;
     24     
     25     while(t<'0' || t>'9'){
     26         if(t=='-')f=1;
     27         t=getchar();
     28     }
     29     
     30     while(t>='0' && t<='9'){
     31         x=(x<<3)+(x<<1)+t-'0';
     32         t=getchar();
     33     }
     34     
     35     if(f)x=-x;
     36 }
     37 
     38 struct xb{  //合并重复后的待建节点 
     39     int v,num;
     40 };
     41 
     42 int c[100010];  //原序列
     43 xb yby[100010];  //合并后的待建序列 
     44 int temp[100010];  //排序用辅助序列
     45 int longtao[100010];  //归并用辅助序列
     46 
     47 int rank_ans;
     48 int pre_ans,succ_ans;
     49 int k,l,r;
     50 
     51 int n,m,i;
     52 int opt,a,b,pos,x;
     53 
     54 void merge(int,int,int);  //归并 
     55 
     56 struct node{  //平衡树节点定义 
     57     int key;
     58     int size,num;
     59     node *ch[2];
     60     
     61     void make(int x){  //新建节点,x为下标,指向待建节点 
     62         key=yby[x].v;
     63         size=num=yby[x].num;
     64         ch[0]=ch[1]=NULL;
     65     }
     66     
     67     void maintain(){
     68         size=num;
     69         if(ch[0]!=NULL)size+=ch[0]->size;
     70         if(ch[1]!=NULL)size+=ch[1]->size;
     71     }
     72 };
     73 
     74 void rotate(node* &,bool);  //旋转 
     75 void insert(node* &,int);  //插入 
     76 void del(node* &,int);  //删除 
     77 void unit(int,int,node* &);  //合并待建序列中的重复元素 
     78 void bst_build(node* &,int,int,int);  //平衡树建树 
     79 int bst_rank(node *,int);  //求排名 
     80 void bst_pre(node *,int);  //求前驱 
     81 void bst_succ(node *,int);  //求后继 
     82 
     83 struct sgt{  //线段树 
     84     node *p[200010];
     85     
     86     void build(int o,int l,int r){
     87         int mid=(l+r)>>1;
     88         
     89         if(l<r){
     90             int lson=o<<1;
     91             int rson=lson|1;
     92             
     93             build(lson,l,mid);
     94             build(rson,mid+1,r);
     95         }
     96         
     97         merge(l,r,mid);
     98         
     99         p[o]=NULL;
    100         unit(l,r,p[o]);
    101     }
    102     
    103     void rank(int o,int l,int r){
    104         if(l>=a && r<=b)rank_ans+=bst_rank(p[o],x)-1;
    105         
    106         else{
    107             int mid=(l+r)>>1;
    108             int lson=o<<1;
    109             int rson=lson|1;
    110             
    111             if(a<=mid)rank(lson,l,mid);
    112             if(b>mid)rank(rson,mid+1,r);
    113         }
    114     }
    115     
    116     void update(int o,int l,int r){
    117         del(p[o],c[pos]);
    118         insert(p[o],x);
    119         
    120         if(l<r){
    121             int mid=(l+r)>>1;
    122             int lson=o<<1;
    123             int rson=lson|1;
    124             
    125             if(pos<=mid)update(lson,l,mid);
    126             else update(rson,mid+1,r);
    127         }
    128     }
    129     
    130     void pre(int o,int l,int r){
    131         if(l>=a && r<=b)bst_pre(p[o],x);
    132         
    133         else{
    134             int mid=(l+r)>>1;
    135             int lson=o<<1;
    136             int rson=lson|1;
    137             
    138             if(a<=mid)pre(lson,l,mid);
    139             if(b>mid)pre(rson,mid+1,r);
    140         }
    141     }
    142     
    143     void succ(int o,int l,int r){
    144         if(l>=a && r<=b)bst_succ(p[o],x);
    145         
    146         else{
    147             int mid=(l+r)>>1;
    148             int lson=o<<1;
    149             int rson=lson|1;
    150             
    151             if(a<=mid)succ(lson,l,mid);
    152             if(b>mid)succ(rson,mid+1,r);
    153         }
    154     }
    155 } tree;
    156 
    157 int main(){
    158     srand(time(0));
    159     
    160     read(n);read(m);
    161     
    162     for(i=1;i<=n;i++){
    163         read(c[i]);
    164         temp[i]=c[i];
    165     }
    166     
    167     tree.build(1,1,n);
    168     
    169     for(i=1;i<=m;i++){
    170         read(opt);
    171         
    172         switch(opt){
    173             case 1:{
    174                 read(a);read(b);read(x);
    175                 
    176                 rank_ans=1;
    177                 tree.rank(1,1,n);
    178                 printf("%d
    ",rank_ans);
    179                 break;
    180             }
    181             
    182             case 2:{
    183                 read(a);read(b);read(k);
    184                 
    185                 l=0;
    186                 r=100000000;
    187                 x=(l+r+1)>>1;
    188                 
    189                 while(l<r){
    190                     rank_ans=1;
    191                     tree.rank(1,1,n);
    192                     
    193                     if(rank_ans>k)r=x-1;
    194                     else l=x;
    195                     
    196                     x=(l+r+1)>>1;
    197                 }
    198                 
    199                 printf("%d
    ",x);
    200                 break;
    201             }
    202             
    203             case 3:{
    204                 read(pos);read(x);
    205                 
    206                 tree.update(1,1,n);
    207                 c[pos]=x;
    208                 break;
    209             }
    210             
    211             case 4:{
    212                 read(a);read(b);read(x);
    213                 
    214                 pre_ans=-inf;
    215                 tree.pre(1,1,n);
    216                 printf("%d
    ",pre_ans);
    217                 break;
    218             }
    219             
    220             case 5:{
    221                 read(a);read(b);read(x);
    222                 
    223                 succ_ans=inf;
    224                 tree.succ(1,1,n);
    225                 printf("%d
    ",succ_ans);
    226                 break;
    227             }
    228         }
    229     }
    230     
    231     return 0;
    232 } 
    233 
    234 void rotate(node* &p,bool f){
    235     node *t=p->ch[f^1];
    236     p->ch[f^1]=t->ch[f];
    237     t->ch[f]=p;
    238     
    239     p->maintain();
    240     t->maintain();
    241     
    242     p=t;
    243 }
    244 
    245 void insert(node* &p,int x){
    246     if(p==NULL){
    247         p=(node *)malloc(sizeof(node));
    248         p->key=x;
    249         p->size=p->num=1;
    250         p->ch[0]=p->ch[1]=NULL;
    251         return;
    252     }
    253     
    254     if(x==p->key){
    255         p->size++;
    256         p->num++;
    257         return;
    258     }
    259     
    260     if(x<p->key){
    261         insert(p->ch[0],x);
    262         p->size++;
    263     }
    264     else{
    265         insert(p->ch[1],x);
    266         p->size++;
    267     }
    268 }
    269 
    270 void del(node* &p,int x){
    271     if(p==NULL)return;
    272     
    273     if(x==p->key){
    274         if(p->num>1){
    275             p->num--;
    276             p->size--;
    277             return;
    278         }
    279         else{
    280             if(p->ch[0]==NULL){
    281                 node* t=p;
    282                 p=p->ch[1];
    283                 free(t);
    284                 return;
    285             }
    286             else if(p->ch[1]==NULL){
    287                 node* t=p;
    288                 p=p->ch[0];
    289                 free(t);
    290                 return;
    291             }
    292             else{
    293                 bool f=rand()&1;
    294                 rotate(p,f);
    295                 del(p->ch[f],x);
    296                 p->size--;
    297             }
    298         }
    299     }
    300     else{
    301         if(x<p->key)del(p->ch[0],x);
    302         else del(p->ch[1],x);
    303         p->size--;
    304     }
    305 }
    306 
    307 void unit(int l,int r,node* &root){
    308     int i;
    309     int p_yby=1;
    310     
    311     yby[1].v=temp[l];
    312     yby[1].num=1;
    313     
    314     for(i=l+1;i<=r;i++){
    315         if(temp[i]==yby[p_yby].v)yby[p_yby].num++;
    316         else{
    317             p_yby++;
    318             yby[p_yby].v=temp[i];
    319             yby[p_yby].num=1;
    320         }
    321     }
    322     
    323     bst_build(root,1,p_yby,(1+p_yby)>>1);
    324 }
    325 
    326 void bst_build(node* &p,int l,int r,int mid){
    327     p=(node *)malloc(sizeof(node));
    328     p->make(mid);
    329     
    330     if(mid-1>=l)bst_build(p->ch[0],l,mid-1,(l+mid-1)>>1);
    331     if(mid+1<=r)bst_build(p->ch[1],mid+1,r,(mid+1+r)>>1);
    332     
    333     p->maintain();
    334 }
    335 
    336 int bst_rank(node *p,int x){
    337     if(p==NULL)return 1;
    338     
    339     int s=0;
    340     if(p->ch[0]!=NULL)s=p->ch[0]->size;
    341     
    342     if(x<p->key)return bst_rank(p->ch[0],x);
    343     else if(x==p->key)return s+1;
    344     else return s+p->num+bst_rank(p->ch[1],x);
    345 }
    346 
    347 void merge(int head,int tail,int mid){
    348     if(head==tail)return;
    349     
    350     int p1=head,p2=mid+1,ph=head;
    351     
    352     while(p1<=mid && p2<=tail){
    353         if(temp[p1]<temp[p2]){
    354             longtao[ph]=temp[p1];
    355             p1++;
    356             ph++;
    357         }
    358         else{
    359             longtao[ph]=temp[p2];
    360             p2++;
    361             ph++;
    362         }
    363     }
    364     
    365     while(p1<=mid){
    366         longtao[ph]=temp[p1];
    367         p1++;
    368         ph++;
    369     }
    370     
    371     while(p2<=tail){
    372         longtao[ph]=temp[p2];
    373         p2++;
    374         ph++;
    375     }
    376     
    377     for(i=head;i<=tail;i++)temp[i]=longtao[i];
    378 }
    379 
    380 void bst_pre(node *p,int x){
    381     if(p==NULL)return;
    382     if(p->key<x){
    383         pre_ans=max(pre_ans,p->key);
    384         bst_pre(p->ch[1],x);
    385     }
    386     else bst_pre(p->ch[0],x);
    387 }
    388 
    389 void bst_succ(node *p,int x){
    390     if(p==NULL)return;
    391     if(p->key>x){
    392         succ_ans=min(succ_ans,p->key);
    393         bst_succ(p->ch[0],x);
    394     }
    395     else bst_succ(p->ch[1],x);
    396 }
  • 相关阅读:
    React.js自学第一天
    优化的34条定律
    JS 打字机效果
    css3 翻书效果
    对象操作
    表单提交验证
    封装cookie组件
    iOS中为网站添加图标到主屏幕
    教你从Win8换回Win7
    关于VB中Print函数在数组中换行的理解
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/7624454.html
Copyright © 2011-2022 走看看