对输入数据我们有如下假定: 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操作不会把光标移动到非法位置。 输入文件没有错误。
1 //STATUS:C++_AC_1296MS_48380KB
2 #include <functional>
3 #include <algorithm>
4 #include <iostream>
5 //#include <ext/rope>
6 #include <fstream>
7 #include <sstream>
8 #include <iomanip>
9 #include <numeric>
10 #include <cstring>
11 #include <cassert>
12 #include <cstdio>
13 #include <string>
14 #include <vector>
15 #include <bitset>
16 #include <queue>
17 #include <stack>
18 #include <cmath>
19 #include <ctime>
20 #include <list>
21 #include <set>
22 #include <map>
23 using namespace std;
24 //using namespace __gnu_cxx;
25 //define
26 #define pii pair<int,int>
27 #define mem(a,b) memset(a,b,sizeof(a))
28 #define lson l,mid,rt<<1
29 #define rson mid+1,r,rt<<1|1
30 #define PI acos(-1.0)
31 //typedef
32 //typedef __int64 LL;
33 //typedef unsigned __int64 ULL;
34 //const
35 const int N=1024*1024*2+10;
36 const int INF=0x3f3f3f3f;
37 const int MOD=100000,STA=8000010;
38 //const LL LNF=1LL<<60;
39 const double EPS=1e-8;
40 const double OO=1e15;
41 const int dx[4]={-1,0,1,0};
42 const int dy[4]={0,1,0,-1};
43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
44 //Daily Use ...
45 inline int sign(double x){return (x>EPS)-(x<-EPS);}
46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
49 template<class T> inline T Min(T a,T b){return a<b?a:b;}
50 template<class T> inline T Max(T a,T b){return a>b?a:b;}
51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
55 //End
56
57 #define Key_value ch[ch[root][1]][0]
58 int pre[N],ch[N][2]; //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量
59 int sz[N],st[N]; //子树规模,内存池
60 int root,tot,top; //根节点,根节点数量,内存池容量
61 //题目特定数目
62 char key[N],s[N];
63 bool rev[N];
64 int n,m,cursor;
65 //debug部分copy from hh
66 void Treaval(int x) {
67 if(x) {
68 Treaval(ch[x][0]);
69 printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d rev = %2d key = %2c\n",x,ch[x][0],ch[x][1],pre[x],sz[x],rev[x],key[x]);
70 Treaval(ch[x][1]);
71 }
72 }
73 void debug() {printf("%d\n",root);Treaval(root);}
74 //以上Debug
75 //新建一个结点
76 void NewNode(int &x,int fa,char c)
77 {
78 if(top)x=st[--top];
79 else x=++tot;
80 key[x]=c;
81 pre[x]=fa;
82 sz[x]=1;
83 rev[x]=0;
84 ch[x][0]=ch[x][1]=0; //左右孩子为空
85 }
86
87 void Push_Up(int x)
88 {
89 sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;
90 }
91
92 void Push_Down(int x)
93 {
94 if(rev[x]){
95 rev[ch[x][0]]^=1;
96 rev[ch[x][1]]^=1;
97 swap(ch[x][0],ch[x][1]);
98 rev[x]=0;
99 }
100 }
101 //旋转,kind为1为右旋,kind为0为左旋
102 void Rotate(int x,int kind)
103 {
104 int y=pre[x],z=pre[y];
105 Push_Down(y);
106 Push_Down(x); //先把y的标记向下传递,再把x的标记往下传递
107 //类似SBT,要把其中一个分支先给父节点
108 ch[y][!kind]=ch[x][kind];
109 pre[ch[x][kind]]=y;
110 //如果父节点不是根结点,则要和父节点的父节点连接起来
111 if(z)ch[z][ch[z][1]==y]=x;
112 pre[x]=z;
113 ch[x][kind]=y;
114 pre[y]=x;
115 Push_Up(y); //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可
116 }
117 //Splay调整,将根为r的子树调整为goal
118 void Splay(int x,int goal)
119 {
120 int y,z,kind;
121 while(pre[x]!=goal){
122 //父节点即是目标位置,goal为0表示,父节点就是根结点
123 y=pre[x];
124 Push_Down(pre[y]);Push_Down(y);Push_Down(x); //设计到反转操作,要先更新,然后在判断!!
125 if(pre[y]==goal){
126 Rotate(x,ch[y][0]==x);
127 }
128 else {
129 kind=ch[pre[y]][0]==y;
130 //两个方向不同,则先左旋再右旋
131 if(ch[y][kind]==x){
132 Rotate(x,!kind);
133 Rotate(x,kind);
134 }
135 //两个方向相同,相同方向连续两次
136 else {
137 Rotate(y,kind);
138 Rotate(x,kind);
139 }
140 }
141 }
142 //更新根结点
143 Push_Up(x);
144 if(goal==0)root=x;
145 }
146
147 void RotateTo(int k,int goal)
148 {
149 int x=root;
150 Push_Down(x);
151 while(sz[ch[x][0]]!=k){
152 if(sz[ch[x][0]]>k)
153 x=ch[x][0];
154 else {
155 k-=sz[ch[x][0]]+1;
156 x=ch[x][1];
157 }
158 Push_Down(x);
159 }
160 Splay(x,goal);
161 }
162 //建树,中间结点先建立,然后分别对区间两端在左右子树建立
163 void BuildTree(int &x,int l,int r,int fa)
164 {
165 if(l>r)return;
166 int mid=(l+r)>>1;
167 NewNode(x,fa,s[mid]);
168 BuildTree(ch[x][0],l,mid-1,x);
169 BuildTree(ch[x][1],mid+1,r,x);
170 Push_Up(x);
171 }
172
173 void Init()
174 {
175 root=top=tot=0;
176 ch[0][0]=ch[0][1]=sz[0]=pre[0]=rev[0]=key[0]=0;
177
178 NewNode(root,0,0);
179 NewNode(ch[root][1],root,0);
180 cursor=0;
181 }
182
183 void Insert(int len)
184 {
185 RotateTo(cursor,0);
186 RotateTo(cursor+1,root);
187 BuildTree(Key_value,0,len-1,ch[root][1]);
188 Push_Up(ch[root][1]);
189 Push_Up(root);
190 }
191
192 void Delete(int n)
193 {
194 RotateTo(cursor,0);
195 RotateTo(cursor+n+1,root);
196 Key_value=0;
197 Push_Up(ch[root][1]);
198 Push_Up(root);
199 }
200
201 void Rotate(int n)
202 {
203 RotateTo(cursor,0);
204 RotateTo(cursor+n+1,root);
205 rev[Key_value]^=1;
206 }
207
208 void Get()
209 {
210 int x=root,k=cursor+1;
211 Push_Down(x);
212 while(sz[ch[x][0]]!=k){
213 if(sz[ch[x][0]]>k)
214 x=ch[x][0];
215 else {
216 k-=sz[ch[x][0]]+1;
217 x=ch[x][1];
218 }
219 Push_Down(x);
220 }
221 printf("%c\n",key[x]);
222 }
223
224 int main()
225 {
226 // freopen("in.txt","r",stdin);
227 int i,j,k;
228 char op[15];
229 while(~scanf("%d",&n))
230 {
231 Init();
232 while(n--){
233 scanf("%s",op);
234 if(op[0]=='M'){
235 scanf("%d",&k);
236 cursor=k?k:0;
237 }
238 else if(op[0]=='I'){
239 scanf("%d",&k);
240 getchar();
241 gets(s);
242 Insert(k);
243 }
244 else if(op[0]=='D'){
245 scanf("%d",&k);
246 Delete(k);
247 }
248 else if(op[0]=='R'){
249 scanf("%d",&k);
250 Rotate(k);
251 }
252 else if(op[0]=='G'){
253 Get();
254 }
255 else if(op[0]=='P'){
256 cursor--;
257 }
258 else {
259 cursor++;
260 }
261 }
262 }
263 return 0;
264 }