此题本是经典的块状链表题,但我听说 Splay 也可以对一个序列进行维护,于是我也写了个 Splay 。
做法很简单,维护一颗以各个字符为结点的伸展树,按文本从左到右的顺序作为各个结点关键字的大小关系。为了实现方便,我加入了一个额外的头结点和一个额外的尾结点。对于各种操作的处理方法:
光标前移、后移、移到第 k 个字符之后:用 pos 记录光标前面的一个字符是伸展树的第几个。初始时 pos 值为 1 。前移和后移分别加 1 或减 1 ,移到第 k 个字符之后则把 pos 赋为 k+1 。更改了 pos 值之后查找到第 pos 个元素,把它 Splay 到根。
插入一段长为 len 的字符串:先把字符串的各个字符按照先后顺序建成一条符合 Splay 性质的链。然后查找到第 pos+1 个元素,将他 Splay 到根的右儿子的位置。将建成的链作为这个元素的左儿子。
删除长度为 len 的字符串:查找第 pos+len+1 个元素并 Splay 到根的右儿子,将此元素的左子树删除。
输出长度为 len 的字符串:和删除类似,查找第 pos+len+1 个元素并 Splay 到根的右儿子,然后输出此元素左子树的中序遍历。由于 Splay 的不平衡,递归很可能爆栈,我采用了模拟递归的方法。
要注意删除和输出时光标后不一定又足够的字符。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> using namespace std; const int MAXV=2*1024*1024+100; struct SplayTree { int VS,cur[MAXV]; struct node { node *p,*lch,*rch; int s,cur; char key; }V[MAXV],*root,*nul; inline SplayTree() { VS=0; nul=V; nul->s=0; } inline node* Newnode(char ch,node *p) { V[++VS].key=ch; V[VS].s=1; V[VS].p=p; V[VS].lch=nul; V[VS].rch=nul; return V+VS; } inline void init() { root=Newnode('#',nul); root->rch=Newnode('#',root); root->s = 2; memset(cur,0,sizeof(cur)); } inline void Updata(node *x) { x->s = x->lch->s + x->rch->s + 1; } inline void LG(node* x) { node* y=x->lch; if (root==x) root=y; if (x==x->p->lch) x->p->lch = y; else x->p->rch = y; y->p = x->p; x->lch = y->rch; y->rch->p = x; y->rch = x; x->p = y; Updata(x); Updata(y); } inline void RG(node* x) { node* y=x->rch; if (root==x) root=y; if (x==x->p->lch) x->p->lch = y; else x->p->rch = y; y->p = x->p; x->rch = y->lch; y->lch->p = x; y->lch = x; x->p = y; Updata(x); Updata(y); } void Splay(node* c,node* f) { while (c->p != f) { if (c->p->p == f) if (c==c->p->lch) LG(c->p); else RG(c->p); else { bool lc=(c==c->p->lch),lp=(c->p==c->p->p->lch); if (lc && lp) { LG(c->p->p); LG(c->p); } if (!lc && !lp) { RG(c->p->p); RG(c->p); } if (lc && !lp) { LG(c->p); RG(c->p); } if (!lc && lp) { RG(c->p); LG(c->p); } } } } void Select(int k,node* f) { node* i=root; while (i->lch->s+1 != k) { if (i->lch->s+1 > k) i=i->lch; else { k -= i->lch->s+1; i=i->rch; } } Splay(i,f); } void Insert(char* str,int len) { Select(root->lch->s+2,root); root->rch->lch = Newnode(str[1],root->rch); node* x=root->rch->lch; x->s = len; for (int i=2; i<=len; i++) { x->rch = Newnode(str[i],x); x=x->rch; x->s = len-i+1; } Updata(root->rch); Updata(root); } void Delete(int len) { int last; if (root->lch->s+len+2 <= root->s) last=root->lch->s+len+2; else last=root->s; Select(last,root); root->rch->lch = nul; Updata(root->rch); Updata(root); } void Get(int len) { int last; if (root->lch->s+len+2 <= root->s) last = root->lch->s+len+2; else last = root->s; Select(last,root); node* i=root->rch->lch; while (i!=root->rch) { if (cur[i-V]==0) { cur[i-V]++; if (i->lch != nul) { i=i->lch; continue; } } if (cur[i-V]==1) { printf("%c",i->key); cur[i-V]++; if (i->rch != nul) { i=i->rch; continue; } } if (cur[i-V]==2) { cur[i-V]=0; i=i->p; } } printf("/n"); } }T; int N,pos; char C[10],S[MAXV]; void init() { scanf("%d/n",&N); T.init(); pos=1; } void solve() { for (int i=1; i<=N; i++) { scanf("%s",C); switch(C[0]) { int k; case 'P': T.Select(--pos,T.nul); break; case 'N': T.Select(++pos,T.nul); break; case 'M': scanf("%d",&k); T.Select(pos=k+1,T.nul); break; case 'I': scanf("%d",&k); for (int i=0; i<k;) { char ch; scanf("%c",&ch); if (ch>=32 && ch<=126) S[++i]=ch; } T.Insert(S,k); break; case 'D': scanf("%d",&k); T.Delete(k); break; case 'G': scanf("%d",&k); T.Get(k); break; } } } int main() { freopen("editor.in","r",stdin); freopen("editor.out","w",stdout); init(); solve(); return 0; }
开始测试 Ambusher 正在编译 Ambusher.editor ...成功 正在测试 Ambusher.editor.1(editor1.in)... 正确 0.020秒 得分: 10 正在测试 Ambusher.editor.2(editor2.in)... 正确 0.287秒 得分: 10 正在测试 Ambusher.editor.3(editor3.in)... 正确 0.269秒 得分: 10 正在测试 Ambusher.editor.4(editor4.in)... 正确 0.266秒 得分: 10 正在测试 Ambusher.editor.5(editor5.in)... 正确 0.319秒 得分: 10 正在测试 Ambusher.editor.6(editor6.in)... 正确 0.325秒 得分: 10 正在测试 Ambusher.editor.7(editor7.in)... 正确 0.310秒 得分: 10 正在测试 Ambusher.editor.8(editor8.in)... 正确 0.379秒 得分: 10 正在测试 Ambusher.editor.9(editor9.in)... 正确 0.553秒 得分: 10 正在测试 Ambusher.editor.10(editor10.in)... 正确 0.717秒 得分: 10 Ambusher.editor 的总分: 100 Ambusher 的总分: 100