splay操作的裸题。(BZOJ1269的简化版)
这道题要求维护一个数列,支持一系列操作(光标的位置用一个pos记录即可):
Move(k):直接把pos赋值为k+1(为什么是k+1,后面再说)
Insert(n,str):先把pos旋转到根节点,再把pos+1旋到根结点的儿子,然后直接在pos+1的左儿子插入str即可
Delete(n):先把pos旋转到根节点,再把pos+n+1旋到根结点的儿子,然后删除pos+k+1的左儿子
Get(n):先把pos旋转到根节点,递归输出n个数
Prev():直接把pos--
Next():直接把pos++
pos赋值为k+1的原因在BZOJ1269的题解中已经说过。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> #define maxn 1024*1024*3 using namespace std; int cnt,root,pos,tot=0,q,k; struct splay { int l,r,size,fa; char data; }a[maxn]; char str[maxn]; void Push_up(int x) { a[x].size=1+a[a[x].l].size+a[a[x].r].size; } void zig(int x) { int y=a[x].fa; int z=a[y].fa; a[y].fa=x,a[x].fa=z; a[y].l=a[x].r,a[a[x].r].fa=y,a[x].r=y; if (a[z].l==y) a[z].l=x; else a[z].r=x; Push_up(y); } void zag(int x) { int y=a[x].fa; int z=a[y].fa; a[y].fa=x,a[x].fa=z; a[y].r=a[x].l,a[a[x].l].fa=y,a[x].l=y; if (y==a[z].l) a[z].l=x; else a[z].r=x; Push_up(y); } void splay(int x,int s) { while (a[x].fa!=s) { int y=a[x].fa; int z=a[y].fa; if (z==s) { if (x==a[y].l) zig(x); else zag(x); } else { if (y==a[z].l) { if (x==a[y].l) zig(y),zig(x); else zag(x),zig(x); } else { if (x==a[y].r) zag(y),zag(x); else zig(x),zag(x); } } } Push_up(x); if (s==0) root=x; } int Findkth(int x,int k) { int s=a[a[x].l].size; if (k==s+1) return x; if (k<=s) return Findkth(a[x].l,k); return Findkth(a[x].r,k-s-1); } int Getmin(int x) { while (a[x].l) x=a[x].l; return x; } void New_Node(int &x,int fa,char c) { x=++tot; a[x].fa=fa; a[x].l=a[x].r=a[x].size=0; a[x].data=c; } void Build(int &x,int fa,int l,int r,char *str) { if (l>r) return; int m=(l+r)>>1; New_Node(x,fa,str[m]); Build(a[x].l,x,l,m-1,str); Build(a[x].r,x,m+1,r,str); Push_up(x); } void Insert(char *str,int l) { int x=Findkth(root,pos); splay(x,0); x=Getmin(a[root].r); splay(x,root); Build(a[x].l,x,0,l-1,str); } void Delet(int k) { int x=Findkth(root,pos); splay(x,0); x=Findkth(root,pos+k+1); splay(x,root); a[a[x].l].fa=0; a[x].l=0; Push_up(x); Push_up(root); } void dg(int x,int k) { if (!a[x].r&&!a[x].l) { cnt++; if (cnt>k) return; printf("%c",a[x].data); return; } if (a[x].l) dg(a[x].l,k); cnt++; if (cnt>k) return; printf("%c",a[x].data); if (a[x].r) dg(a[x].r,k); } void Print(int k) { int x=Findkth(root,pos); splay(x,0); cnt=0; dg(a[root].r,k); printf("\n"); } int main() { scanf("%d",&q); root=tot=0; pos=1; Build(root,0,0,1," "); while (q--) { scanf("%s",str); if (str[0]=='I') { scanf("%d",&k); getchar(); for (int i=0;i<k;i++) { str[i]=getchar(); if (str[i]=='\n') {i--;continue;} } Insert(str,k); } else if (str[0]=='M') { scanf("%d",&k); pos=k+1; } else if (str[0]=='D') { scanf("%d",&k); Delet(k); } else if (str[0]=='P') pos--; else if (str[0]=='N') pos++; else { scanf("%d",&k); Print(k); } } return 0; }
小结:
1.第一次交TLE了,因为在写Get的时候我直接找排在第i位的数(Findkth(i)),每一次复杂度为O(nlogn),有n次Get操作复杂度就会变成O(n^2logn)!!