Description
这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义: 文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。 编写一个程序: 建立一个空的文本编辑器。 从输入文件中读入一些操作指令并执行。 对所有执行过的GET操作,将指定的内容写入输出文件。
Input
输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。
Output
依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。
Sample Input
10 Insert 13 Balanced eert Move 2 Delete 5 Next Insert 7 editor Move 0 Get Move 11 Rotate 4 Get
Sample Output
B
t
HINT
对输入数据我们有如下假定: MOVE操作不超过50 000个,INSERT、DELETE和ROTATE操作作的总个数不超过6 000,GET操作不超过20 000个,PREV和NEXT操作的总个数不超过20 000。 所有INSERT插入的字符数之和不超过2M(1M=1 024*1 024)。 DELETE操作、ROTATE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。 输入文件没有错误。
Solution
这里模版已经尽量短了。可以用循环代替的非递归代码都已经换掉了,效率一般就是了。
实现操作:
1.(已知)move k:移动光标到目标,初始为0
2.(已知)prev:光标前移一个字符
3.(已知)next:光标后移一个字符
4.insert n s:在光标后插入长度为n的字符串s光标位置不变
5.delete n 删除光标后的n个字符,光标位置不变
6.rotate n 反转光标后的n个字符,光标位置不变
7.get 输出光标后一个字符,光标位置不变
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int Rin(){ int x=0,c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45))f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; return x*f; } int n; char a[1<<22],b[10]; struct node { node *ch[2],*p; char v;int s,rev; inline void relax() { if(rev)ch[0]->revIt(),ch[1]->revIt(); rev=0; } inline void pu(){s=ch[0]->s+ch[1]->s+1;} inline bool d(){return p->ch[1]==this;} inline void setc(node *a,int d){ch[d]=a;a->p=this;} inline void revIt(){rev^=1;swap(ch[0],ch[1]);} }; node *null=new node(); node *root=null; inline node *newnode(node *f,char val) { node *re=new node(); re->s=1; re->v=val; re->rev=0; re->ch[0]=re->ch[1]=null; re->p=f; return re; } inline void rot(node*&o){ node*p=o->p; p->relax(); o->relax(); bool d=o->d(); p->p->setc(o,p->d()); p->setc(o->ch[!d],d); o->setc(p,!d); p->pu();o->pu(); if(p==root)root=o; } inline void splay(node*o,node*f){ while(o->p!=f){ if(o->p->p==f) rot(o); else o->d()^o->p->d()?(rot(o),rot(o)):(rot(o->p),rot(o)); o->pu(); } } node *build(int l,int r) { if(l>r) return null; int mid=(l+r)>>1; node *o=newnode(o,a[mid]); o->setc(build(l,mid-1),0); o->setc(build(mid+1,r),1); o->pu(); return o; } void del(node* &x) { if(x->ch[0]!=null)del(x->ch[0]); if(x->ch[1]!=null)del(x->ch[1]); delete x; } node *kth(node *x,int k) { for(node *x=root;;){ x->relax(); if(k<=x->ch[0]->s) x=x->ch[0]; else{ k-=x->ch[0]->s; if(!(k^1))return x; x=x->ch[1];k--; } } } int main() { n=Rin(); root=build(0,1); root->p=null; for(int x,t=0,i=1;i<=n;i++) { scanf("%s",b); if(b[0]=='M') t=Rin(); else if(b[0]=='I') { x=Rin(); while((a[0]=getchar())==' '||a[0]==' '); if(x>1) gets(a+1); splay(kth(root,t+1),null); splay(kth(root,t+2),root); root->ch[1]->setc(build(0,x-1),0); root->ch[1]->pu(); root->pu(); } else if(b[0]=='D') { x=Rin(); splay(kth(root,t+1),null); splay(kth(root,t+x+2),root); del(root->ch[1]->ch[0]); root->ch[1]->ch[0]=null; root->ch[1]->pu(); root->pu(); } else if(b[0]=='R') { x=Rin(); splay(kth(root,t+1),null); splay(kth(root,t+x+2),root); root->ch[1]->ch[0]->revIt(); root->ch[1]->pu(); root->pu(); } else if(b[0]=='G') { splay(kth(root,t+2),null); printf("%c ",root->v); } else if(b[0]=='P') t--; else t++; } }
rope大法好
#include<cstdio> #include<ext/rope> #include<iostream> using namespace std; using namespace __gnu_cxx; inline int Rin(){ int x=0,c=getchar(),f=1; for(;c<48||c>57;c=getchar()) if(!(c^45))f=-1; for(;c>47&&c<58;c=getchar()) x=(x<<1)+(x<<3)+c-48; return x*f; } int n,pos,x,l; rope<char>a,b,tmp; char sign[10],ch[1<<22],rch[1<<22]; int main(){ n=Rin(); while(n--){ scanf("%s",sign); switch(sign[0]){ case'M':pos=Rin();break; case'P':pos--;break; case'N':pos++;break; case'G':putchar(a[pos]);putchar(' ');break; case'I': x=Rin(); l=a.length(); for(int i=0;i<x;i++){ do{ch[i]=getchar();} while(ch[i]==' '); rch[x-i-1]=ch[i]; } ch[x]=rch[x]='