Splay
Splay序列维护的模板题了……为了便于处理边界情况,我们可以先插入两个空格当作最左端和最右端,然后……其实本题主要考察的就是Build、splay和Findkth这三个操作,我们可以实现一个splay(x,s)操作,使x结点旋转到s结点的下方(如果s为0则x旋转到根),这样可以方便地提取出要处理的区间。
这份模板我还是比较满意的,因为写的没那么长……
1 /************************************************************** 2 Problem: 1269 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:1236 ms 7 Memory:46220 kb 8 ****************************************************************/ 9 10 //BZOJ 1269 11 #include<vector> 12 #include<cstdio> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 inline int getint(){ 23 int v=0,sign=1; char ch=getchar(); 24 while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();} 25 while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();} 26 return v*sign; 27 } 28 const int N=2e6+1000,INF=~0u>>2; 29 typedef long long LL; 30 /******************tamplate*********************/ 31 int n; 32 char s[N],v[N]; 33 int c[N][2],size[N],fa[N],root,tot; 34 bool rev[N]; 35 #define L c[x][0] 36 #define R c[x][1] 37 void Push_up(int x){ 38 size[x]=size[L]+size[R]+1; 39 } 40 void Push_down(int x){ 41 if (rev[x]) {rev[L]^=rev[x]; rev[R]^=rev[x]; rev[x]=0; swap(L,R);} 42 } 43 void New_node(int &x,int f,int key){ 44 x=++tot; 45 fa[x]=f; v[x]=key; 46 L=R=rev[x]=0; 47 size[x]=1; 48 } 49 void Build(int &x,int f,int l,int r){ 50 if (l>r) return; 51 int m=l+r>>1; 52 New_node(x,f,s[m]); 53 Build(L,x,l,m-1); 54 Build(R,x,m+1,r); 55 Push_up(x); 56 } 57 void Rotate(int x){ 58 int y=fa[x],z=fa[y],l=c[y][1]==x,r=l^1; 59 c[z][c[z][1]==y]=x; 60 fa[x]=z; fa[y]=x; fa[c[x][r]]=y; 61 c[y][l]=c[x][r]; c[x][r]=y; 62 Push_up(y); 63 } 64 int st[N],top; 65 void Preview(int x){ 66 top=0; st[++top]=x; 67 for(;fa[x];x=fa[x]) 68 st[++top]=fa[x]; 69 D(i,top,1) Push_down(st[i]); 70 } 71 void splay(int x,int s=0){ 72 int y; 73 for(Preview(x);fa[x]!=s;Rotate(x)) 74 if ((fa[y=fa[x]])!=s) Rotate(c[y][1]==x^c[fa[y]][1]==y ? x : y); 75 Push_up(x); 76 if (!s) root=x; 77 } 78 int kth(int x,int k){ 79 if (rev[x]) Push_down(x); 80 if (size[L]+1==k) return x; 81 else if (size[L]>=k) return kth(L,k); 82 else return kth(R,k-size[L]-1); 83 } 84 int main(){ 85 #ifndef ONLINE_JUDGE 86 freopen("1269.in","r",stdin); 87 freopen("1269.out","w",stdout); 88 #endif 89 n=getint(); 90 s[0]=s[1]=' '; 91 Build(root,0,0,1); 92 int x,now=1; char cmd[10]; 93 F(i,1,n){ 94 scanf("%s",cmd); 95 // cout <<"cmd: "<<cmd<<endl; 96 if (cmd[0]=='I'){ 97 x=getint();//gets(s); 98 gets(s); 99 splay(kth(root,now)); 100 splay(kth(root,now+1),root); 101 Build(c[c[root][1]][0],c[root][1],0,x-1); 102 }else if (cmd[0]=='M'){ 103 now=getint()+1; 104 }else if (cmd[0]=='D'){ 105 x=getint(); 106 splay(kth(root,now)); splay(kth(c[root][1],x+1),root); 107 c[c[root][1]][0]=0; Push_up(c[root][1]); Push_up(root); 108 }else if (cmd[0]=='R'){ 109 x=getint(); 110 splay(kth(root,now)); splay(kth(c[root][1],x+1),root); 111 rev[c[c[root][1]][0]]^=1; 112 }else if (cmd[0]=='G'){ 113 printf("%c ",v[kth(root,now+1)]); 114 }else if (cmd[0]=='N'){ 115 now++; 116 }else if (cmd[0]=='P'){ 117 now--; 118 } 119 } 120 return 0; 121 }
1269: [AHOI2006]文本编辑器editor
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2273 Solved: 838
[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操作不会把光标移动到非法位置。 输入文件没有错误。