• [模板]洛谷T2042 NOI2005 维护数列 Splay


    PS:某大佬讲,当心情特别好or特别不好的时候,可以来攻略这个题。。。果然萌新足足被这题恶心了半个月。。。

    进入正题:

    这道题题意如此之裸-Splayの究极进化,那么就没有什么好讲的,直接说搞法好了。。。

    为了代码写起来方便,萌新封装得可能有些过,若不合诸位大佬的口味还请见谅~

    节点node结构体定义:

    key:节点原值;size:子树大小;ch[2]:子树指针;

    set_pd:记录是否打了MAKE-SAME的懒标记;setv:MAKE-SAME的修改值;turn:记录是否旋转;

    sum:子树元素总和;lmax,rmax,zdh:当前节点所控制区间的最大前缀和、最大后缀和、最大子段和。

    成员函数:

    maintain():维护节点信息;

    update_same():打MAKE-SAME的懒标记;

    update_rev():打REVERSE的懒标记;

    pushdown():下放懒标记;

    cmp(int x):求在当前节点所控制区间中,排名为x的元素相对于当前节点的位置,0为左,1为右,-1为当前节点自身;

    son_order(int x,bool d):求在当前节点所控制区间中,排名为x的元素在d指向的子树中的排名。

    主程序函数:

    rotate():萌新采用了先下放再考虑如何旋转的写法,所以不必考虑改变旋转方向之类的东西。。。注意下放、维护就好了;

    splay():此函数,萌新的自行研制写法,相对大佬们的代码,看上去长了许多。。。不过也可以放心食用啦~无父指针Splay赛高~

    build():建立完全平衡的BST,此题中应用这种建树方式,可极大地提高代码速度;

    recycle():回收删除的区间所占用的空间,如果没有这个,会导致个别点MLE;

    get_range():

    这个函数的功能是抽取区间。。。

    为什么要写这个呢?因为萌新太弱了。。。

    我们知道,在抽取区间时,对边界情况,直接Splay就解决不了了;

    这时一般会用“在头和尾加虚拟节点”的方法;

    萌新曾试着这样写过。。。但最终没能解决虚拟节点的信息维护问题,尤其是最大子段和什么的。。。

    于是放弃,采用了略为繁琐的分类讨论写法,具体如下:

    1.若区间为整个序列,则不作任何操作,root即可代表整个序列;

    2.若区间为[1,x],其中x<n,则将x+1号元素splay至root,则root->ch[0]即为该区间;

    3.若区间为[x,n],其中x>1,则采取类似上面的操作;

    4.若区间为[l,r],其中1<l<=r<n,那么将l-1、r+1分别splay至root、root->ch[1],则root->ch[1]->ch[0]即为该区间。

    操作完后,返回一个值,用于在后续操作中进行对不同情况的识别。

    work():依据不同的区间情况和不同的指令,进行相应操作。

    change():依据不同的区间情况进行对相关节点的信息维护。

    大坑警示!!!个别点中,操作的区间可能长度为0!!!

    萌新就是因为这个问题而莫名RE了好久。。。后来终于对照某大佬的代码才发现了问题。。。

    代码如下:

      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 
     15 #define inf 2147483647
     16 
     17 using namespace std;
     18 
     19 void read(int &x){
     20     x=0;
     21     char t=getchar();
     22     bool f=0;
     23     
     24     while(t<'0' || t>'9'){
     25         if(t=='-')f=1;
     26         t=getchar();
     27     }
     28     
     29     while(t>='0' && t<='9'){
     30         x=(x<<3)+(x<<1)+t-'0';
     31         t=getchar();
     32     }
     33     
     34     if(f)x=-x;
     35 }
     36 
     37 struct node{
     38     int key;
     39     int size;
     40     node *ch[2];
     41     
     42     bool set_pd;
     43     int setv;
     44     bool turn;
     45     
     46     int sum;
     47     
     48     int lmax;
     49     int rmax;
     50     int zdh;
     51     
     52     void maintain(){
     53         size=1;
     54         if(ch[0]!=NULL)size+=ch[0]->size;
     55         if(ch[1]!=NULL)size+=ch[1]->size;
     56         
     57         sum=key;
     58         if(ch[0]!=NULL)sum+=ch[0]->sum;
     59         if(ch[1]!=NULL)sum+=ch[1]->sum;
     60         
     61         if(ch[0]==NULL && ch[1]==NULL){
     62             lmax=rmax=max(0,key);
     63             zdh=key;
     64         }
     65         else if(ch[1]==NULL){
     66             lmax=max(ch[0]->lmax,ch[0]->sum+key);
     67             rmax=max(0,key+ch[0]->rmax);
     68             zdh=max(ch[0]->zdh,ch[0]->rmax+key);
     69         }
     70         else if(ch[0]==NULL){
     71             lmax=max(0,key+ch[1]->lmax);
     72             rmax=max(ch[1]->rmax,ch[1]->sum+key);
     73             zdh=max(ch[1]->zdh,key+ch[1]->lmax);
     74         }
     75         else{
     76             lmax=max(ch[0]->lmax,ch[0]->sum+key+ch[1]->lmax);
     77             rmax=max(ch[1]->rmax,ch[1]->sum+key+ch[0]->rmax);
     78             zdh=max(max(ch[0]->zdh,ch[1]->zdh),ch[0]->rmax+key+ch[1]->lmax);
     79         }
     80     }
     81     
     82     void update_same(int fix){
     83         set_pd=1;
     84         key=setv=fix;
     85         
     86         sum=fix*size;
     87         
     88         lmax=rmax=max(0,sum);
     89         zdh=max(sum,key);
     90         
     91         turn=0;  //打了MAKE-SAME之后就可以无视旋转了
     92     }
     93     
     94     void update_rev(){
     95         turn^=1;
     96         
     97         lmax^=rmax;
     98         rmax^=lmax;
     99         lmax^=rmax;  //在上层节点抽取本节点信息时,要求必须在旋转时交换lmax和rmax
    100     }
    101     
    102     void pushdown(){
    103         if(set_pd){
    104             if(ch[0]!=NULL)ch[0]->update_same(setv);
    105             if(ch[1]!=NULL)ch[1]->update_same(setv);
    106             
    107             set_pd=0;
    108             turn=0;
    109         }
    110         if(turn){
    111             node *t=ch[0];
    112             ch[0]=ch[1];
    113             ch[1]=t;
    114             
    115             if(ch[0]!=NULL)ch[0]->update_rev();
    116             if(ch[1]!=NULL)ch[1]->update_rev();
    117             
    118             turn=0;
    119         }
    120     }
    121     
    122     int cmp(int x){
    123         int s=0;
    124         if(ch[0]!=NULL)s=ch[0]->size;
    125         
    126         if(x<=s)return 0;
    127         else if(x==s+1)return -1;
    128         else return 1;
    129     }
    130     
    131     int son_order(int x,bool d){
    132         if(d==0)return x;
    133         else{
    134             if(ch[0]==NULL)return x-1;
    135             else return x-ch[0]->size-1;
    136         }
    137     }
    138 };
    139 
    140 void rotate(node* &,bool);  //没有自带对当前根节点的懒标记下放 
    141 void splay(node* &,int);  //按照排名伸展 
    142 void build(node* &,int,int,int);
    143 void recycle(node *);
    144 
    145 int get_range();
    146 void work(int);
    147 void change();
    148 
    149 node *root=NULL;
    150 node *temp;
    151 
    152 int longtao[500010];
    153 
    154 char s[15];
    155 int n,m,i,j;
    156 int pos,tot,fix,kind;
    157 
    158 int main(){
    159     read(n);read(m);
    160     
    161     for(i=1;i<=n;i++)read(longtao[i]);
    162     build(root,1,n,(1+n)>>1);
    163     
    164     for(i=1;i<=m;i++){
    165         scanf("%s",s);
    166         
    167         switch(s[2]){
    168             case 'S':{
    169                 read(pos);read(tot);
    170                 if(tot==0)break;
    171                 
    172                 for(j=1;j<=tot;j++)read(longtao[j]);
    173                 temp=NULL;
    174                 build(temp,1,tot,(1+tot)>>1);
    175                 
    176                 if(pos==0){
    177                     splay(root,1);
    178                     root->ch[0]=temp;
    179                     root->maintain();
    180                 }
    181                 else if(pos==root->size){
    182                     splay(root,inf);
    183                     root->ch[1]=temp;
    184                     root->maintain();
    185                 }
    186                 else{
    187                     splay(root,pos);
    188                     splay(root->ch[1],1);
    189                     root->ch[1]->ch[0]=temp;
    190                     root->ch[1]->maintain();
    191                     root->maintain();
    192                 }
    193                 
    194                 break;
    195             }
    196             
    197             case 'L':{
    198                 read(pos);read(tot);
    199                 if(tot==0)break;
    200                 
    201                 kind=get_range();
    202                 work(2);
    203                 change();
    204                 
    205                 break;
    206             }
    207             
    208             case 'K':{
    209                 read(pos);read(tot);read(fix);
    210                 if(tot==0)break;
    211                 
    212                 kind=get_range();
    213                 work(3);
    214                 change();
    215                 
    216                 break;
    217             }
    218             
    219             case 'V':{
    220                 read(pos);read(tot);
    221                 if(tot==0)break;
    222                 
    223                 kind=get_range();
    224                 work(4);
    225                 change();
    226                 
    227                 break;
    228             }
    229             
    230             case 'T':{
    231                 read(pos);read(tot);
    232                 if(tot==0){
    233                     printf("0
    ");
    234                     break;
    235                 }
    236                 
    237                 kind=get_range();
    238                 work(5);
    239                 
    240                 break;
    241             }
    242             
    243             case 'X':{
    244                 printf("%d
    ",root->zdh);
    245                 
    246                 break;
    247             }
    248         }
    249     }
    250     
    251     return 0;
    252 }
    253 
    254 void rotate(node* &p,bool f){
    255     node *t=p->ch[f^1];
    256     
    257     t->pushdown();
    258     
    259     p->ch[f^1]=t->ch[f];
    260     t->ch[f]=p;
    261     
    262     p->maintain();
    263     t->maintain();
    264     
    265     p=t;
    266 }
    267 
    268 void splay(node* &p,int x){
    269     p->pushdown();
    270     
    271     int d1=p->cmp(x);
    272     if(d1==-1 || p->ch[d1]==NULL)return;
    273     
    274     p->ch[d1]->pushdown();
    275     
    276     int x2=p->son_order(x,d1);
    277     int d2=p->ch[d1]->cmp(x2);
    278     if(d2==-1 || p->ch[d1]->ch[d2]==NULL){
    279         rotate(p,d1^1);
    280         return;
    281     }
    282     else{
    283         int x3=p->ch[d1]->son_order(x2,d2);
    284         
    285         splay(p->ch[d1]->ch[d2],x3);
    286         
    287         if(d1==d2){
    288             rotate(p,d1^1);
    289             rotate(p,d2^1);
    290         }
    291         else{
    292             rotate(p->ch[d1],d1);
    293             rotate(p,d2);
    294         }
    295     }
    296 }
    297 
    298 void build(node* &p,int l,int r,int mid){
    299     p=(node *)malloc(sizeof(node));
    300     
    301     p->key=longtao[mid];
    302     p->ch[0]=p->ch[1]=NULL;
    303     p->set_pd=0;
    304     p->turn=0;
    305     
    306     if(mid-1>=l)build(p->ch[0],l,mid-1,(l+mid-1)>>1);
    307     if(mid+1<=r)build(p->ch[1],mid+1,r,(mid+1+r)>>1);
    308     
    309     p->maintain();
    310 }
    311 
    312 void recycle(node *p){
    313     if(p->ch[0]!=NULL)recycle(p->ch[0]);
    314     if(p->ch[1]!=NULL)recycle(p->ch[1]);
    315     
    316     free(p);
    317 }
    318 
    319 int get_range(){
    320     if(tot==root->size)return 1;
    321     else if(pos==1){
    322         splay(root,pos+tot);
    323         return 2;
    324     }
    325     else if(pos+tot-1==root->size){
    326         splay(root,pos-1);
    327         return 3;
    328     }
    329     else{
    330         splay(root,pos-1);
    331         splay(root->ch[1],tot+1);
    332         return 4;
    333     }
    334 }
    335 
    336 void work(int f){
    337     node **t;
    338     if(kind==1)t=&root;
    339     if(kind==2)t=&(root->ch[0]);
    340     if(kind==3)t=&(root->ch[1]);
    341     if(kind==4)t=&(root->ch[1]->ch[0]);
    342     
    343     if(f==2){
    344         recycle(*t);
    345         (*t)=NULL;
    346     }
    347     else if(f==3)(*t)->update_same(fix);
    348     else if(f==4)(*t)->update_rev();
    349     else printf("%d
    ",(*t)->sum);
    350 }
    351 
    352 void change(){
    353     if(kind==2 || kind==3)root->maintain();
    354     else if(kind==4){
    355         root->ch[1]->maintain();
    356         root->maintain();
    357     }
    358 }
  • 相关阅读:
    笔记 : windows系统下 命令行 php --version 的版本与phpinfo()版本不一致问题
    笔记 : WampServe加装PHP版本(7.2.3)为例
    Browsersync结合gulp和nodemon实现express全栈自动刷新
    PHP与JSP简单比较
    BDD 与DSL 入门
    1.display:flex布局笔记
    Css预处理器---Less(三)
    python_30期_第2讲【字符串&运算符】
    python_30期_第5讲【while循环+for循环】
    class_05py作业
  • 原文地址:https://www.cnblogs.com/running-coder-wfh/p/7351916.html
Copyright © 2020-2023  润新知