终于知道为什么人人都感慨Splay功能强大了。这道题更像是块状链表的裸题,而且块状链表巨小无比的常数跑起来也非常劲啊。但是我寒假照着板子敲了一遍......敲得我心累啊,敲完以后我就有了我以后再也不会写分块了的念头。但是最近写树套树三道两道被卡常,而看着分块水过一道一道,我心里又慌了......
说正题。
首先,对于这道题目,我们的Splay是基于size平衡的,而基于size平衡的Splay百分之九十的情况我们可以用单旋,且因为单旋常数较小,往往有着优秀的表现,编码复杂度直降一个台阶。
然后题目要求的操作对于功能强大的Splay来说简直小菜一碟,我们只需要提取相应区间按要求做就好了。
唯一需要特别注意的是对于初始化以及插入操作,而初始化是基于如何插入的。
对于一般情况来说,考虑在cur后插入len个字符,我们按如下方式实现。
1:将size==cur的节点x伸展到根。
2:将size==cur+1的节点y伸展到根。
上述操作后节点x一定是节点y的左子节点,且y的右子节点为空。
3:对于y的右子节点我们执行build操作。
build操作就与一般的build操作相同,按size二分。
接下来我们考虑初始化。
初始的cur指向位置0,而在我们递归进行splay的过程中我们使用s[l[x]]+1==k的方式查找size==k的节点,而显然如果cur==0,这个过程会无限进行下去。对于这个问题,我们使cur初始值为1,并建立一个虚拟根节点,这样size[root]==1,size[l[root]]==0,成功解决。
接下来我们要查找size==cur+1的节点,而现在的splay树中只有一个节点,显然也是无法成功的。所以我们再建立一个节点,建立根节点的左子节点或右子节点都可以,这样我们就可以成功实现两个splay操作,继而实现插入操作了。
接着,因为我们的空文本的起始位置cur的值定为1,而题目给出的数据对应是0,所以对于MOVE(x)操作,我们总是将x+1的值赋给cur,这样就可以成功对应我们的初始化了。
说明:我的单旋splay模(mu)板来自于千古神犇MIKE。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<cstdlib> using namespace std; const int M=2500000+10; struct SplayTree { int root,cnt,cur,l[M],r[M],s[M]; char v[M],c[M]; SplayTree():root(0),cnt(0),cur(0) { memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); memset(s,0,sizeof(s)); memset(v,0,sizeof(v)); memset(c,0,sizeof(c)); } void reset() { // 初始化. root=++cnt,l[root]=++cnt,cur=1; s[root]=2,s[l[root]]=1; } void update(int x) { s[x]=s[l[x]]+s[r[x]]+1; } void l_rot(int &x) { int y=r[x]; r[x]=l[y],l[y]=x; update(x),update(y); x=y; } void r_rot(int &x) { int y=l[x]; l[x]=r[y],r[y]=x; update(x),update(y); x=y; } void splay(int &x,int k) { int i=s[l[x]]+1; if(k==i) return ; else if(k<i) splay(l[x],k),r_rot(x); else splay(r[x],k-i),l_rot(x); } void move(int x,bool P) { P?cur=x+1:cur+=x; } void build(int &x,int ll,int rr) { if(ll>rr) return ; int mid=(ll+rr)>>1; if(!x) x=++cnt; v[x]=c[mid],s[x]=rr-ll+1; build(l[x],ll,mid-1); build(r[x],mid+1,rr); } void insert(int len) { splay(root,cur); splay(root,cur+1); for(int i=1;i<=len;i++) for(c[i]=getchar();c[i]<32||c[i]>126;c[i]=getchar()); build(r[l[root]],1,len); update(l[root]); update(root); } void delet(int len) { splay(root,cur); splay(root,cur+len+1); r[l[root]]=0; update(l[root]); update(root); } void prints(int len) { splay(root,cur); splay(root,cur+len+1); dfs(r[l[root]]); printf("\n"); } void dfs(int x) { if(l[x]) dfs(l[x]); printf("%c",v[x]); if(r[x]) dfs(r[x]); } }t; int main() { freopen("editor2003.in","r",stdin); freopen("editor2003.out","w",stdout); int m,x; char str[17]; scanf("%d",&m); t.reset(); for(int i=1;i<=m;i++) { scanf("%s",str); if(str[0]==‘M‘) scanf("%d",&x),t.move(x,1); else if(str[0]==‘I‘) scanf("%d",&x),t.insert(x); else if(str[0]==‘D‘) scanf("%d",&x),t.delet(x); else if(str[0]==‘G‘) scanf("%d",&x),t.prints(x); else if(str[0]==‘P‘) t.move(-1,0); else t.move(1,0); } return 0; }