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

Posted Running-Coder

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模板]洛谷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\n");
234                     break;
235                 }
236                 
237                 kind=get_range();
238                 work(5);
239                 
240                 break;
241             }
242             
243             case X:{
244                 printf("%d\n",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\n",(*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 }

 

以上是关于[模板]洛谷T2042 NOI2005 维护数列 Splay的主要内容,如果未能解决你的问题,请参考以下文章

NOI2005维护数列

NOI 2005维护数列

BZOJ1500 NOI2005 维修数列 平衡树

BZOJ1500: [NOI2005]维修数列

[NOI2005]维修数列

bzoj1500 [NOI2005]维修数列