【SPLAY】SPOJ1470维护数列

来源:互联网 发布:mac自带p图软件 编辑:程序博客网 时间:2024/06/05 16:53

       BZOJ跪了我找了好多OJ才又找到维护数列这个题~话说SPOJ好像比较慢的样子~我找别人以前在BZOJ上AC的程序在SPOJ上竟然TLE了~加了读入优化还是TLE~囧~这算个什么事~今天把splay的数组实现改成了指针实现以后终于AC掉了~完全不知道我的splay哪里写慢了QAQ

       splay总体来说就是转来转去转来转去【转晕了诶】各种操作都是在旋转的基础上完成的。splay因为不需要维护树的严格平衡,可以实现很多其它平衡树不能完成的操作。总体来说splay的功能有如下一些:

       单点插入、查询、删除(所有平衡树都可以)

       单点、成段更新(其它平衡树不能、线段树和splay可以)(呃~好像其它平衡树可以单点更新的样子呢喵)

       成段插入、删除、区间翻转(其它平衡树和线段树都不能,只有splay可以)

       也就是说,splay可以代替线段树,但是和线段树比起来代码量过大了QAQ

对区间的操作方式是:把区间左端点的左边一位转到根,右端点的右边一位转到根的右子树,这样根的右子树的左子树就是要操作的区间。开始建树时要在树上建两-INF的结点保证区间的两个端点一定存在。

2012-12-26

关于splay的双旋转,要这样旋转的原因是为了维护splay的相对平衡,如果总是转x结点一直转到根那么一条链转完以后还是一条链,而使用双旋转则可以使旋转后的splay变得相对平衡。这一部分在杨思雨的论文里有详细的图解。

更具体一些的可以围观Crash神的论文

囧~话说平衡树我是先学的SBT,没学splay是因为我当时不会线段树,本来是要交给蛋蛋去学的~然后我之所以不会线段树是因为觉得他俩都会了我就不学了QAQ然后~我还是学了~学完以后发现这玩意好简单……然后开始折腾splay【是这货折腾我】……理论到是不难~写起来还真是各种纠结~围观了Crash神的论文和各位神的代码终于搞明白了OTL

下面送上我的splay模板~个人觉得写得还是很清晰的~

/*    插入:INSERT pos n c1...cn (pos后面插入n个数字)    删除:DELETE pos n (删除pos开始的n个数字)    修改:MAKE-SAME pos n c (pos开始的n个数字修改为c)    翻转:REVERSE pos n (pos开始的n个数字翻转)    求和:GET-SUM pos n (pos开始的n个数字求和)    求和最大的子序列:MAX-SUM (整个区间的和最大的子序列)*/#include <cstdio>#include <iostream>using namespace std;#define INF 1<<30#define N 500010int n,m;int num[N];struct node{node *ch[2],*pre;int sz,val,sum,ls,rs,ss;bool lzy1;int lzy2;};struct SplayTree{node *root,*null,*pool[N],data[N];int n,cnt,top;void rotate(node *x,int f)//旋转{node *y=x->pre,*z=y->pre;push_down(y);push_down(x);y->ch[!f]=x->ch[f];x->ch[f]->pre=y;x->ch[f]=y;y->pre=x;x->pre=z;if(x->pre!=null) z->ch[z->ch[1]==y]=x;push_up(y);}void splay(node *x,node *goal)//把x节点转到goal下面,goal为0表示转到根{push_down(x);while (x->pre!=goal){if(x->pre->pre==goal) rotate(x,x->pre->ch[0]==x);else{node *y=x->pre,*z=y->pre;int f=(z->ch[0]==y);if(y->ch[f]==x) rotate(x,!f);else rotate(y,f);rotate(x,f);}}push_up(x);if(goal==null) root=x;}void rotateto(int k,node *goal)//把第k位转到goal下面{node *x=root;push_down(x);while (x->ch[0]->sz!=k){if(k<x->ch[0]->sz) x=x->ch[0];else{k-=x->ch[0]->sz+1;x=x->ch[1];}push_down(x);}splay(x,goal);}//以上函数基本不用变void clear(){n=top=0;null=newnode(-INF);null->sz=null->sum=0;null->val=null->ls=null->rs=null->ss=-INF;null->lzy1=0;null->lzy2=-INF;root=newnode(-INF);root->ch[1]=newnode(-INF);root->ch[1]->pre=root;root->sz=2;}node *newnode(int c){node *x;if (top) x=pool[top--];else x=&data[n++];x->ch[0]=x->ch[1]=x->pre=null;x->sz=1;x->val=x->ls=x->rs=x->ss=x->sum=c;x->lzy1=0;x->lzy2=-INF;return x;}void push_up(node *x){node *lx=x->ch[0],*rx=x->ch[1];x->sz=1+lx->sz+rx->sz;x->sum=x->val+lx->sum+rx->sum;x->ls=max(lx->ls,lx->sum+x->val+max(0,rx->ls));x->rs=max(rx->rs,rx->sum+x->val+max(0,lx->rs));x->ss=max(0,lx->rs)+x->val+max(0,rx->ls);x->ss=max(x->ss,max(lx->ss,rx->ss));}void update_rev(node *x){if(x==null) return;swap(x->ch[0],x->ch[1]);swap(x->ls,x->rs);x->lzy1^=1;}void update_same(node *x,int v){if(x==null) return;x->val=v;x->sum=v*x->sz;x->ss=x->ls=x->rs=max(v,v*x->sz);x->lzy2=v;}void push_down(node *x){if(x->lzy1){update_rev(x->ch[0]);update_rev(x->ch[1]);x->lzy1=0;}if(x->lzy2!=-INF){update_same(x->ch[0],x->lzy2);update_same(x->ch[1],x->lzy2);x->lzy2=-INF;}}void init(int pos,int tot){clear();cnt=tot;rotateto(pos,null);rotateto(pos+1,root);root->ch[1]->ch[0]=build(1,tot,root->ch[1]);push_up(root->ch[1]);push_up(root);}node *build(int l,int r,node *f){if(l>r) return null;push_down(f);int mid=(l+r)>>1;node *x=newnode(num[mid]);x->ch[0]=build(l,mid-1,x);x->ch[1]=build(mid+1,r,x);x->pre=f;push_up(x);return x;}void ins(int pos,int len){cnt+=len;rotateto(pos,null);rotateto(pos+1,root);root->ch[1]->ch[0]=build(1,len,root->ch[1]);push_up(root->ch[1]);push_up(root);}void erase(node *x){if(x==null) return;pool[++top]=x;erase(x->ch[0]);erase(x->ch[1]);}void del(int l,int r){rotateto(l-1,null);rotateto(r+1,root);node *key=root->ch[1]->ch[0];root->ch[1]->ch[0]=null;cnt-=key->sz;erase(key);push_up(root->ch[1]);push_up(root);}void change(int l,int r,int c){rotateto(l-1,null);rotateto(r+1,root);node *key=root->ch[1]->ch[0];update_same(key,c);push_up(root->ch[1]);push_up(root);}void flip(int l,int r){rotateto(l-1,null);rotateto(r+1,root);node *key=root->ch[1]->ch[0];update_rev(key);}int get_sum(int l,int r){rotateto(l-1,null);rotateto(r+1,root);node *key=root->ch[1]->ch[0];return key->sum;}int max_sum(){rotateto(0,null);rotateto(cnt+1,root);node *key=root->ch[1]->ch[0];return key->ss;}void print(node *x){if(x->ch[0]!=null) print(x->ch[0]);printf("%d ",x->val);if(x->ch[1]!=null) print(x->ch[1]);}}spl;int main (){ int tt; int i,j,t; int a,b,c; char op[30]; scanf("%d",&tt); while (tt--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&num[i]); spl.init(0,n); /*spl.print(spl.root); printf("\n"); return 0;*/ while (m--) { scanf("%s",op); if(op[0]=='I') { scanf("%d%d",&a,&n); for(i=1;i<=n;i++) scanf("%d",&num[i]); spl.ins(a,n); }else if(op[0]=='D') { scanf("%d%d",&a,&b); spl.del(a,a+b-1); }else if(op[0]=='M' && op[2]=='K') { scanf("%d%d%d",&a,&b,&c); spl.change(a,a+b-1,c); }else if(op[0]=='R') { scanf("%d%d",&a,&b); spl.flip(a,a+b-1); }else if(op[0]=='G') { scanf("%d%d",&a,&b); printf("%d\n",spl.get_sum(a,a+b-1)); } else if(op[0]=='M') printf("%d\n",spl.max_sum()); } }return 0;}