POJ3580[memo] 旋转吧,splay!

来源:互联网 发布:node express 编辑:程序博客网 时间:2024/06/16 16:44

重新写了一下splay,并且琢磨自己的版。

以前看过这道题,感觉操作好繁琐,不做。

今天看了一下,恩,有必要再写一下splay,先拿这道题练手。


题意:

给定序列,维护6个操作:

ADD l r x  把[l,r]加上x

REVERSE l r  把[l,r]翻转

REVOLVE l r t 把[l,r]这一段向后滚动t次,  比如1,2,3  滚动2次变成  2,3,1

INSERT x y  在x后面插入y

DELTEL x删掉第x个元素

MIN l r 询问[l,r]中的最小值


对于第一个操作,用lazy标记维护pushdown一下就好了

对于第二个操作,用bool 型的rev维护pushdown一下就好了

第三个操作,先将t对区间长度取mod,然后分成前面的区间和后t个元素的区间,交换这两个区间的先后,我们可以先把两个区间分别翻转,再把整个区间翻转,这样影响的只是前后两个区间的位置,不影响里面的元素排列。


第四个操作,把x旋到根,x+1旋到根的右儿子,root->r->l一定为空,直接插入元素即可


第五个操作,把x-1旋到根,x+1旋到根的右儿子,root->r-l就是x,删掉就好了


第6个,在splay维护一个最小值,每次pushdown和rotate的时候更新一下,到时候照样的l-1旋到根,r+1选到根的右边,查询root->r-l即可。


PS:注意如果splay单纯地维护[1,n],对于l-1,r+1可能会越界,需要特判.

但是特判是在是麻烦,代码量增长不少,所以为了简便,我提前插入了0和n+1两个节点,之后涉及到区间的都把区间标号+1  


然后就没有了,我debug还是调了那么久,毕竟数据结构的题嘛,不过要比我想象的顺利一些。


PS被坑点:

1.DEL之后将空节点选到了根(果断RE,都空了,咋旋)   

2.REVOLVE那里开始写的特别复杂,后来改成这样,不过把又把区间标号向右移了1,算上翻转那里又+1,就把区间标号向右移了2次。


splay的性质是,把操作过的点旋到根,这样在一种玄学的推理下单词查询复杂度降为均摊logn .  所以我把insert和min涉及到的点旋到了根,应该会快些吧- -



然后就附上代码:

#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<queue>#include<cmath>using namespace std;const int maxn=100000+20;struct node{node *f;node *ch[2];int sz,key,m;//size key minint lazy;//adddbool rev;//reversevoid rs(){sz=1+ch[0]->sz+ch[1]->sz;m=key;m=min(m,ch[0]->m);m=min(m,ch[1]->m);}}S[maxn<<2],*root,*null;int ncnt;int n,m;void clear(){ncnt=0;null=&S[ncnt];null->sz=0;null->key=0x3f3f3f3f;null->m=0x3f3f3f3f;null->lazy=null->rev=0;root=null;}node *newnode(int key){node *p=&S[++ncnt];p->sz=1;p->key=p->m=key;p->lazy=p->rev=0;p->ch[0]=p->ch[1]=p->f=null;return p;}void pushdown(node *u){if(u==null)return ;if(u->lazy){if(u->ch[0]!=null){u->ch[0]->m+=u->lazy;u->ch[0]->key+=u->lazy;u->ch[0]->lazy+=u->lazy;}if(u->ch[1]!=null){u->ch[1]->m+=u->lazy;u->ch[1]->key+=u->lazy;u->ch[1]->lazy+=u->lazy;}u->lazy=0;}if(u->rev){swap(u->ch[0],u->ch[1]);if(u->ch[0]!=null)u->ch[0]->rev^=1;if(u->ch[1]!=null)u->ch[1]->rev^=1;u->rev^=1;}}void rotate(node *u){node *f=u->f;if(f==null)return ;node *ff=f->f;pushdown(u);pushdown(f);int d=u==f->ch[1];int dd=(ff!=null)?(f==ff->ch[1]):0;if(u->ch[d^1]!=null)u->ch[d^1]->f=f;f->ch[d]=u->ch[d^1];u->ch[d^1]=f;f->f=u;if(ff!=null)ff->ch[dd]=u;u->f=ff;f->rs();u->rs();}void splay(node *u,node *p){pushdown(u);while(u->f!=p){node *f=u->f;node *ff=f->f;if(ff==p){rotate(u);break;}int d=u==f->ch[1];int dd=f==ff->ch[1];if(d==dd)rotate(f);else rotate(u);rotate(u);}if(p==null)root=u;u->rs();}void insert(node *&u,node *&fa,int key){if(u==null){u=newnode(key);u->f=fa;splay(u,null);return ;}insert(u->ch[1],u,key);u->rs();}char ss[20];void find(int k,node *p)//找到排名为k的并旋到p下 {node *u=root;while(1){pushdown(u);if(u->ch[0]->sz+1==k)break;if(u->ch[0]->sz>=k)u=u->ch[0];else{k-=u->ch[0]->sz+1;u=u->ch[1];}}splay(u,p);}void Add(int l,int r,int x)//本来是要把l-1旋到根,r+1旋到//根下,加了一个0,就是把l旋到根,r+2旋到根下 {find(l,null);find(r+2,root);node *u=root->ch[1]->ch[0];u->lazy+=x;u->key+=x;u->m+=x;root->ch[1]->rs();root->rs();}void REVERSE(int l,int r)//本来是操作l-1,r+1选到根 {find(l,null);find(r+2,root);node *u=root->ch[1]->ch[0];u->rev^=1;} void REVOLVE(int l,int r,int x)//对于[l,r]这段区间向右移t位,相当于把最后t位放到前面 {int t=(x%(r-l+1)+(r-l+1))%(r-l+1);//分成两段[l,r-t]    [r-t+1,r] REVERSE(l,r-t);REVERSE(r-t+1,r);REVERSE(l,r);}void INSERT(int l,int x){find(l+1,null);find(l+2,root);root->ch[1]->ch[0]=newnode(x);root->ch[1]->ch[0]->f=root->ch[1];root->ch[1]->rs();root->rs();splay(root->ch[1]->ch[0],null);}void DEL(int x){find(x,null);find(x+2,root);root->ch[1]->ch[0]=null;root->ch[1]->rs();root->rs();}void MIN(int l,int r){find(l,null);find(r+2,root);printf("%d\n",root->ch[1]->ch[0]->m);splay(root->ch[1]->ch[0],null);}int main(){freopen("memo.in","r",stdin);freopen("memo.out","w",stdout);clear();scanf("%d",&n);insert(root,null,0);for(int i=1;i<=n;i++){int x;scanf("%d",&x);insert(root,null,x);}insert(root,null,1000001);int l,r,x;scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%s",ss);if(ss[0]=='A'){scanf("%d%d%d",&l,&r,&x);Add(l,r,x);}else if(ss[0]=='R'&&ss[3]=='E'){scanf("%d%d",&l,&r);REVERSE(l,r);}else if(ss[0]=='R'&&ss[3]=='O'){scanf("%d%d%d",&l,&r,&x);REVOLVE(l,r,x);}else if(ss[0]=='I'){scanf("%d%d",&l,&x);INSERT(l,x);}else if(ss[0]=='D'){scanf("%d",&x);DEL(x);}else{scanf("%d%d",&l,&r);MIN(l,r);}}return 0;}

         

继续回顾splay

1 0
原创粉丝点击