题意:
做了一套简单的练习后,用Splay处理区间问题就变得非常容易了。
总的来说,所有的splay有关,涉及区间的问题,都会基于select操作(其实就是根据排名找点)
node * find_id(node *x,int k){pushdown(x);int sz=x->ch[0]->sz;if(sz>=k)return find_id(x->ch[0],k);if(sz+1==k)return x;return find_id(x->ch[1],k-sz-1);
}
我写的递归版本,比较容易理解,但最好改为循环实现。
然后,有了这一操作,我们可以将Splay tree中的任意一个区间“提取”出来
例如翻转操作:
void Rev(int k,int len){node *x=find_id(root,k-1);//区间之前的一个点splay(x,NIL);node *y=find_id(root,k+len);//区间之后的一个点splay(y,x);//将y旋转至x的右儿子,这样一来,我们要的区间,就是以y的左儿子为根的子树y->ch[0]->tag^=1;pushdown(y->ch[0]);pushup(y);pushup(x);
}
这样的做法很显然需要预设两个哨兵节点,一个在最前,一个最后。
其实所有的区间操作,无非就是这样一个既定的套路,唯一有所不同的,也只有在pushup和pushdown中才能体现。
也正是因此,pushup和pushdown的操作具有很强的灵活性,分别概述过于复杂,我在这里就简单提及一下这两个操作的注意事项:
pushup操作的目的,是将子节点的信息重新反馈到当前节点。因此任何涉及更改子节点的信息后,都必须使用pushup操作。是一个上传的过程。
pushdown则与之相反,是将当前节点的信息(懒标记为主)下传给子节点,必须遵守一个原则:即与pushup操作不冲突。也就是说,任何时候,当你使用一次pushdown,再做一次pushup,是不能够将pushdown操作所改变的信息抹去的。这一点在本题很有体现:在区间赋值操作中,如果仅仅更新当前节点,是不能够满足要求的,因为当再做一次pushup操作时,子节点的懒标记并未处理,造成当前节点又被恢复原样。
以上就是Splay处理区间问题的方法,
对于节点维护哪些信息,可以当做线段树来考虑,因为同为二叉树,线段树和平衡树有很多相同之处。
对于本题的做法,就再简单提及一点:
本题必须使用释放空间的方式来完成删除,否则会T
成套路的方法,没必要刷过多的题,做一两道经典的就可以了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#define SF scanf
#define PF printf
#define MAXN 500100
#define INF 0x3FFFFFFF
using namespace std;
struct node{node *ch[2],*fa;int tag,sz,sum,maxs,maxl,maxr;int key,flag;
}tree[MAXN];
node *root,*NIL=&tree[0],*ncnt=&tree[1];
bool flag=0;
stack<int> emt;
int a[MAXN];
void Read(int &x){char c;bool flag=0;while(c=getchar(),c!=EOF&&c!='-'&&(c<'0'||c>'9'));if(c=='-'){flag=1;c=getchar();}x=c-'0';while(c=getchar(),c!=EOF&&c>='0'&&c<='9')x=x*10+c-'0';if(flag)x=-x;
}
node *Newnode(int val){node *p=tree+emt.top();emt.pop();p->ch[0]=p->ch[1]=p->fa=NIL;p->sz=1;p->flag=INF;p->tag=0;p->key=p->sum=p->maxs=val;p->maxl=p->maxr=max(0,val);return p;
}
void pushup(node *x){x->sz=x->ch[1]->sz+x->ch[0]->sz+1;x->sum=x->ch[0]->sum+x->ch[1]->sum+x->key;x->maxs=max(max(x->ch[0]->maxs,x->ch[1]->maxs),x->ch[0]->maxr+x->ch[1]->maxl+x->key);x->maxl=max(x->ch[0]->maxl,x->ch[0]->sum+x->key+x->ch[1]->maxl);x->maxr=max(x->ch[1]->maxr,x->ch[1]->sum+x->key+x->ch[0]->maxr);
}
void pushdownx(node *x){if(x->tag==1){if(x->ch[0]!=NIL)x->ch[0]->tag^=1;if(x->ch[1]!=NIL)x->ch[1]->tag^=1;swap(x->ch[0],x->ch[1]);swap(x->maxl,x->maxr);x->tag=0;}if(x->flag!=INF){if(x->ch[0]!=NIL)x->ch[0]->flag=x->flag;if(x->ch[1]!=NIL)x->ch[1]->flag=x->flag;x->key=x->flag;x->sum=(x->flag)*(x->sz);x->maxl=max(0,x->sum);x->maxr=x->maxl;x->maxs=max(x->flag,x->sum);x->flag=INF;}
}
void pushdown(node *x){if(x->tag==1){if(x->ch[0]!=NIL)x->ch[0]->tag^=1;if(x->ch[1]!=NIL)x->ch[1]->tag^=1;swap(x->ch[0],x->ch[1]);swap(x->maxl,x->maxr);x->tag=0;}if(x->flag!=INF){if(x->ch[0]!=NIL)x->ch[0]->flag=x->flag;if(x->ch[1]!=NIL)x->ch[1]->flag=x->flag;x->key=x->flag;x->sum=(x->flag)*(x->sz);x->maxl=max(0,x->sum);x->maxr=x->maxl;x->maxs=max(x->flag,x->sum);x->flag=INF;}if(x->ch[0]!=NIL)pushdownx(x->ch[0]);if(x->ch[1]!=NIL)pushdownx(x->ch[1]);
}
void Rotate(node *x){node *y=x->fa;pushdown(y);pushdown(x);int d=(x==y->ch[0]);x->fa=y->fa;if(y->fa!=NIL)y->fa->ch[y->fa->ch[1]==y]=x;y->ch[!d]=x->ch[d];if(x->ch[d]!=NIL)x->ch[d]->fa=y;x->ch[d]=y;y->fa=x;if(root==y)root=x;pushup(y);pushup(x);
}
void splay(node *x,node *rt){node *y,*z;while(x->fa!=rt){y=x->fa;z=y->fa;if(z==rt){Rotate(x);}else{if((y==z->ch[0])^(x==y->ch[0]))Rotate(x);elseRotate(y);Rotate(x);}}
}
node * find_id(node *x,int k){pushdown(x);int sz=x->ch[0]->sz;if(sz>=k)return find_id(x->ch[0],k);if(sz+1==k)return x;return find_id(x->ch[1],k-sz-1);
}
node * findnext(node *x,int d){pushdown(x);while(x->ch[d]!=NIL){x=x->ch[d];pushdown(x);}return x;
}
void build(int l,int r,node *fa,int d){int mid=(l+r)>>1;node *x=Newnode(a[mid]);x->fa=fa;if(fa!=NIL)fa->ch[d]=x;elseroot=x;if(l==r)return ;if(mid!=l)build(l,mid-1,x,0);build(mid+1,r,x,1);pushup(x);
}
node * Ins(int k,int val){node *x=find_id(root,k);splay(x,NIL);if(x->ch[1]==NIL){x->ch[1]=Newnode(val);x->ch[1]->fa=x;pushup(x);return x->ch[1];}node *y=findnext(x->ch[1],0);splay(y,x);y->ch[0]=Newnode(val);y->ch[0]->fa=y;pushup(y);pushup(x);return y->ch[0];
}
void Fre(node *x){if(x==NIL)return ;emt.push(x-tree);Fre(x->ch[0]);Fre(x->ch[1]);
}
void Del(int k,int len){node *x=find_id(root,k-1);splay(x,NIL);node *y=find_id(root,k+len);splay(y,x);Fre(y->ch[0]);y->ch[0]=NIL;pushup(y);pushup(x);
}
void Mak(int k,int len,int val){node *x=find_id(root,k-1);splay(x,NIL);node *y=find_id(root,k+len);splay(y,x);y->ch[0]->flag=val;pushdown(y->ch[0]);pushup(y);pushup(x);
}
void Rev(int k,int len){node *x=find_id(root,k-1);splay(x,NIL);node *y=find_id(root,k+len);splay(y,x);y->ch[0]->tag^=1;pushdown(y->ch[0]);pushup(y);pushup(x);
}
void Get(int k,int len){node *x=find_id(root,k-1);splay(x,NIL);node *y=find_id(root,k+len);splay(y,x);PF("%d\n",y->ch[0]->sum);
}
void Mas(){PF("%d\n",root->maxs);
}
void print(node *x){if(x==NIL)return ;pushdown(x);print(x->ch[0]);//PF("[id:%d val(%d) {%d lson:%d rson:%d fa:(%d)}]\n ",x-tree,x->key,x->maxs,x->ch[0]-tree,x->ch[1]-tree,x->fa-tree);PF("%d ",x->key);print(x->ch[1]);
}
int n,m;
int k,len,val;
char s[20];
int main(){//freopen("sequence7.in","r",stdin);//freopen("data.out","w",stdout);Read(n);Read(m);a[0]=-INF;a[n+1]=-INF;for(int i=1;i<=n;i++)SF("%d",&a[i]);for(int i=1;i<=500050;i++)emt.push(i);NIL->ch[0]=NIL->ch[1]=NIL->fa=NIL;NIL->maxs=-INF;build(0,n+1,NIL,0);//print(root);for(int i=1;i<=m;i++){SF("%s",s);if(s[0]=='I'){Read(k);Read(len);if(len==0)continue;Read(val);node *x=Ins(k+1,val);for(int i=2;i<=len;i++){Read(val);x->ch[1]=Newnode(val);x->ch[1]->fa=x;x=x->ch[1];}node *x1=x;while(x!=NIL){pushup(x);x=x->fa;}splay(x1,NIL);}else if(s[0]=='D'){Read(k),Read(len);//SF("%d%d",&k,&len);k++;Del(k,len);}else if(s[0]=='R'){Read(k),Read(len);//SF("%d%d",&k,&len);k++;Rev(k,len);}else if(s[0]=='G'){Read(k),Read(len);//SF("%d%d",&k,&len);k++;Get(k,len);}else if(s[2]=='K'){Read(k),Read(len),Read(val);//SF("%d%d%d",&k,&len,&val);k++;Mak(k,len,val);}else{Mas();}//print(root);//PF("\n-----------------------------\n");}
}
2017就是我们的喜悦,
我们的挫败,
我们的成就,
我们的悔恨,
是我们封存的标本。
幸好,明天我们还会忘记新的事物,
所以我们不害怕时间,
时间会向前奔跑,
我们也会。