对输入数据我们有如下假定: 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操作不会把光标移动到非法位置。 输入文件没有错误。
这题操作比较多,但其实都是splay的经典操作,熟练掌握以后条理就很清晰了,写的也很简单。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int maxn = 3e6;
int T, root, x;
char s[maxn];
struct Splays
{
const static int maxn = 3e6; //节点个数
const static int INF = 0x7FFFFFFF; //int最大值
int ch[maxn][2], F[maxn], sz; //左右儿子,父亲节点和节点总个数
int C[maxn], R[maxn];
char S[maxn];
int Node(int f, char s) { S[sz] = s; C[sz] = 1; R[sz] = ch[sz][0] = ch[sz][1] = 0; F[sz] = f; return sz++; }//申请一个新节点
void clear(){ sz = 1; ch[0][0] = ch[0][1] = F[0] = 0; C[0] = 0; }//清空操作
void pushdown(int x)
{
if (!R[x]) return;
R[ch[x][0]] ^= 1; R[ch[x][1]] ^= 1;
swap(ch[x][0], ch[x][1]); R[x] = 0;
}
void rotate(int x, int k)
{
int y = F[x]; ch[y][!k] = ch[x][k]; F[ch[x][k]] = y;
if (F[y]) ch[F[y]][y == ch[F[y]][1]] = x;
F[x] = F[y]; F[y] = x; ch[x][k] = y;
C[x] = C[y]; C[y] = C[ch[y][0]] + C[ch[y][1]] + 1;
}
void Splay(int x, int r)
{
for (int fa = F[r]; F[x] != fa;)
{
if (F[F[x]] == fa) { rotate(x, x == ch[F[x]][0]); return; }
int y = x == ch[F[x]][0], z = F[x] == ch[F[F[x]]][0];
y^z ? (rotate(x, y), rotate(x, z)) : (rotate(F[x], z), rotate(x, y));
}
}
void build(int fa, int &x, int l, int r, char *s)
{
if (l > r) return;
int mid = l + r >> 1;
x = Node(fa, s[mid]);
build(x, ch[x][0], l, mid - 1, s);
build(x, ch[x][1], mid + 1, r, s);
C[x] += C[ch[x][0]] + C[ch[x][1]];
}
void Move(int &x, int y)
{
for (int i = x; i;)
{
pushdown(i);
if (y < C[ch[i][0]]) { i = ch[i][0]; continue; }
if (y == C[ch[i][0]]) { Splay(i, x); x = i; break; }
y -= C[ch[i][0]] + 1; i = ch[i][1];
}
}
void Delete(int &x, int y)
{
for (int i = ch[x][1]; i;)
{
pushdown(i);
if (y < C[ch[i][0]]) { i = ch[i][0]; continue; }
if (y == C[ch[i][0]]) { Splay(i, ch[x][1]); ch[x][1] = i; break; }
y -= C[ch[i][0]] + 1; i = ch[i][1];
}
int add = C[ch[ch[x][1]][0]];
ch[ch[x][1]][0] = 0; C[x] -= add; C[ch[x][1]] -= add;
}
void Rotate(int &x, int y)
{
for (int i = ch[x][1]; i;)
{
pushdown(i);
if (y < C[ch[i][0]]) { i = ch[i][0]; continue; }
if (y == C[ch[i][0]]) { Splay(i, ch[x][1]); ch[x][1] = i; break; }
y -= C[ch[i][0]] + 1; i = ch[i][1];
}
R[ch[ch[x][1]][0]] ^= 1;
}
void Get(int &x)
{
for (int i = ch[x][1]; i; i = ch[i][0])
{
pushdown(i);
if (!ch[i][0]) { Splay(i, ch[x][1]); ch[x][1] = i; break; }
}
printf("%c\n", S[ch[x][1]]);
}
void Prev(int &x)
{
for (int i = ch[x][0]; i; i = ch[i][1])
{
pushdown(i);
if (!ch[i][1]) { Splay(i, x); x = i; break; }
}
}
void Next(int &x)
{
for (int i = ch[x][1]; i; i = ch[i][0])
{
pushdown(i);
if (!ch[i][0]) { Splay(i, x); x = i; break; }
}
}
void Insert(int &x, int y)
{
gets(s); gets(s);
int root = 0;
build(0, root, 0, y - 1, s);
for (int i = ch[x][1]; i; i = ch[i][0])
{
pushdown(i);
if (!ch[i][0]) { Splay(i, ch[x][1]); ch[x][1] = i; break; }
}
ch[ch[x][1]][0] = root; F[root] = ch[x][1];
C[x] += C[root]; C[ch[x][1]] += C[root];
}
}solve;
int main()
{
cin >> T;
root = 0; solve.clear();
s[0] = s[1] = 0;
solve.build(0, root, 0, 1, s);
while (T--)
{
scanf("%s", s);
if (s[0] == 'M') scanf("%d", &x), solve.Move(root, x);
if (s[0] == 'D') scanf("%d", &x), solve.Delete(root, x);
if (s[0] == 'R') scanf("%d", &x), solve.Rotate(root, x);
if (s[0] == 'G') solve.Get(root);
if (s[0] == 'P') solve.Prev(root);
if (s[0] == 'N') solve.Next(root);
if (s[0] == 'I') scanf("%d", &x), solve.Insert(root, x);
}
return 0;
}