BZOJ_1269_文本编辑器_[AHOI2006]_(Spaly)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1269
和BZOJ_1507很像的题,多了一个反转操作,还是Splay简单区间操作的模板题.
1269: [AHOI2006]文本编辑器editor
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3223 Solved: 1203
[Submit][Status][Discuss]
Description
这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义: 文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文 本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空 的。 编写一个程序: 建立一个空的文本编辑器。 从输入文件中读入一些操作指令并执行。 对所有执行过的GET操作,将指定的内容写入输出文件。
Input
输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。
Output
依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。
Sample Input
Insert 13
Balanced eert
Move 2
Delete 5
Next
Insert 7
editor
Move 0
Get
Move 11
Rotate 4
Get
Sample Output
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操作不会把光标移动到非法位置。 输入文件没有错误。
Source
分析
之前的操作和BZOJ_1507相同,多了一个反转操作:
递归地将左右子树调换位置,为了节约时间,打上标记即可.
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn=(1<<21)+5; 6 7 int n,at,cur,x; 8 char str[maxn],s[10]; 9 10 struct Splay{ 11 struct node{ 12 node* ch[2],*pa; 13 char v; int s; bool rev; 14 node(char v,node* t):v(v){ ch[0]=ch[1]=pa=t; s=1; rev=false; } 15 bool d() { return pa->ch[1]==this; } 16 void setc(node* t,bool d) { ch[d]=t; t->pa=this; } 17 void push_up() { s=ch[0]->s+ch[1]->s+1; } 18 void push_down(){//向下传递反转 19 if(rev){ 20 node* c0=ch[0],* c1=ch[1]; 21 setc(c1,0); setc(c0,1);//调换左右子树的位置(貌似可以直接用swap,但刚开始还是自己写吧) 22 ch[0]->rev^=true; ch[1]->rev^=true; 23 rev=false; 24 } 25 } 26 }*root,*null; 27 Splay(){ 28 null=new node('\0',NULL); null->s=0; 29 root=new node('?',null); 30 node* t=new node('!',null); 31 root->setc(t,1); 32 root->push_up(); 33 } 34 void rot(node* o){ 35 node* pa=o->pa; bool d=o->d(); 36 pa->push_down(); o->push_down();//因为会改变o和pa,所以先把标记传递下去. 37 pa->pa->setc(o,pa->d()); 38 pa->setc(o->ch[!d],d); 39 o->setc(pa,!d); 40 pa->push_up(); 41 if(pa==root) root=o; 42 } 43 void splay(node* o,node* pa){ 44 o->push_down();//如果需要转的话,在转的时候会向下传递,但如果不转的话,就在这里向下传递. 45 while(o->pa!=pa){ 46 if(o->pa->pa==pa) rot(o); 47 else o->d()==o->pa->d()?(rot(o->pa),rot(o)):(rot(o),rot(o)); 48 } 49 o->push_up(); 50 } 51 node* kth(int k){ 52 node* t=root; k++; 53 for(t->push_down();;t->push_down()){//每次顺便把标记传递下去. 54 int s=t->ch[0]->s+1; 55 if(s==k) return t; 56 if(k>s) k-=s,t=t->ch[1]; 57 else t=t->ch[0]; 58 } 59 } 60 node* find(int l,int r){ 61 node* L=kth(l); splay(L,null); 62 node* R=kth(r); splay(R,L); 63 return R; 64 } 65 node* build(int l,int r){ 66 if(l==r) return new node(str[l],null); 67 if(l>r) return null; 68 int m=l+(r-l)/2; 69 node* t=new node(str[m],null); 70 t->setc(build(l,m-1),0); 71 t->setc(build(m+1,r),1); 72 t->push_up(); 73 return t; 74 } 75 void insert(int at,int cur){ 76 node* t=find(at,at+1); 77 t->setc(build(0,cur),0); t->push_up();//因为在find函数中t是被splay过的,在splay中已经向下传递过标记了,所以这里不必再传递(remove函数中相同). 78 splay(t,null); 79 } 80 void remove(int at,int n){ 81 node* t=find(at,at+n+1); 82 t->setc(null,0); t->push_up(); 83 splay(t,null); 84 } 85 void setrev(int at,int n){//反转函数 86 node* t=find(at,at+n+1); 87 t->ch[0]->rev^=true; 88 t->push_down(); 89 } 90 void print(node* o){ 91 if(o==null) return; 92 o->push_down();//先向下传递,不然会错. 93 print(o->ch[0]); 94 printf("%c",o->v); 95 print(o->ch[1]); 96 } 97 void print(int at,int n){ 98 node* t=find(at,at+n+1); 99 print(t->ch[0]); 100 printf("\n"); 101 } 102 }tree; 103 104 int main(){ 105 scanf("%d",&n); 106 while(n--){ 107 scanf("%s",s); 108 if(s[0]=='I'){ 109 scanf("%d",&x); 110 cur=0; 111 while(x--){ 112 while(str[cur]=getchar(),str[cur]=='\n'); 113 cur++; 114 } 115 cur--; 116 tree.insert(at,cur); 117 } 118 else if(s[0]=='M') scanf("%d",&at); 119 else if(s[0]=='D'){ 120 scanf("%d",&x); 121 tree.remove(at,x); 122 } 123 else if(s[0]=='G') tree.print(at,1); 124 else if(s[0]=='R'){ 125 scanf("%d",&x); 126 tree.setrev(at,x); 127 } 128 else if(s[0]=='P') at--; 129 else at++; 130 } 131 return 0; 132 }