BZOJ_1507_Editor_[NOI2003]_(Splay)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=1507
简单区间操作的模板题
1507: [NOI2003]Editor
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3092 Solved: 1244
[Submit][Status][Discuss]
Description
Input
输 入文件editor.in的第一行是指令条数t,以下是需要执行的t个操作。其中: 为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。 除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。 这里我们有如下假定: MOVE操作不超过50000个,INSERT和DELETE操作的总个数不超过4000,PREV和NEXT操作的总个数不超过200000。 所有INSERT插入的字符数之和不超过2M(1M=1024*1024),正确的输出文件长度不超过3M字节。 DELETE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作必然不会试图把光标移动到非法位置。 输入文件没有错误。 对C++选手的提示:经测试,最大的测试数据使用fstream进行输入有可能会比使用stdio慢约1秒。
Output
输出文件editor.out的每行依次对应输入文件中每条GET指令的输出。
Sample Input
15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 15
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 15
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22
Sample Output
.\/.
abcde^_^f.\/.ghijklmno
abcde^_^f.\/.ghijklmno
HINT
Source
分析
和BZOJ_1269很像,而且更简单.
首先加入一个起始字符和尾字符(因为我们解决问题的办法都是在两个区间之间进行的).
操作:
1.插入:把at转到根节点,把at+1转到根节点的右儿子,然后在at+1的左儿子处插入即可.
2.移动:直接输入到at即可.
3.删除:把at转到根节点,把at+n+1转到根节点的右儿子,然后把at+n+1的左儿子直接改成null即可.
4.&5.移动光标就at--,at++即可.
1 #include <cstdio> 2 #include <algorithm> 3 using namespace std; 4 5 const int maxn=(2<<21)+5,oo=~0u>>1; 6 7 int n,x,at,cur; 8 char str[maxn],s[10]; 9 10 struct Splay{ 11 struct node{ 12 node* ch[2],* pa; 13 char v; int s; 14 node(int v,node* t):v(v){ ch[0]=ch[1]=pa=t; s=1; } 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 }*root,*null; 19 Splay(){ 20 null=new node('\0',NULL); null->s=0; 21 root=new node('\0',null); 22 node* t=new node('\0',null); 23 root->setc(t,1); 24 root->push_up(); 25 } 26 void rot(node* o){ 27 node* pa=o->pa; bool d=o->d(); 28 pa->pa->setc(o,pa->d()); 29 pa->setc(o->ch[!d],d); 30 o->setc(pa,!d); 31 pa->push_up(); 32 if(pa==root) root=o; 33 } 34 void splay(node* o,node* pa){ 35 while(o->pa!=pa){ 36 if(o->pa->pa==pa) rot(o); 37 else o->d()==o->pa->d()?(rot(o->pa),rot(o)):(rot(o),rot(o)); 38 } 39 o->push_up(); 40 } 41 node* kth(int k){ 42 k++; 43 for(node* t=root;;){ 44 int s=t->ch[0]->s+1; 45 if(s==k) return t; 46 if(k>s) k-=s,t=t->ch[1]; 47 else t=t->ch[0]; 48 } 49 } 50 node* build(int l,int r){ 51 if(l==r) return new node(str[l],null); 52 if(l>r) return null; 53 int m=l+(r-l)/2; 54 node* t=new node(str[m],null); 55 t->setc(build(l,m-1),0); 56 t->setc(build(m+1,r),1); 57 t->push_up(); 58 return t; 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 void insert(int at,int cur){ 66 node* t=find(at,at+1); 67 t->setc(build(0,cur),0); t->push_up(); 68 splay(t,null); 69 } 70 void remove(int at,int n){ 71 node* t=find(at,at+n+1); 72 t->setc(null,0); t->push_up(); 73 splay(t,null); 74 } 75 void print(node* o){ 76 if(o==null) return; 77 print(o->ch[0]); 78 printf("%c",o->v); 79 print(o->ch[1]); 80 } 81 void print(int at,int n){ 82 node* t=find(at,at+n+1); 83 print(t->ch[0]); 84 printf("\n"); 85 } 86 }tree; 87 88 int main(){ 89 scanf("%d",&n); 90 while(n--){ 91 scanf("%s",s); 92 if(s[0]=='I'){ 93 cur=0; 94 scanf("%d",&x); 95 while(x--){ 96 while(str[cur]=getchar(),str[cur]=='\n'); 97 cur++; 98 } 99 cur--; 100 tree.insert(at,cur); 101 } 102 else if(s[0]=='M') scanf("%d",&at); 103 else if(s[0]=='D'){ 104 scanf("%d",&x); 105 tree.remove(at,x); 106 } 107 else if(s[0]=='G'){ 108 scanf("%d",&x); 109 tree.print(at,x); 110 } 111 else if(s[0]=='P') at--; 112 else at++; 113 } 114 return 0; 115 }