题意:N个数,J个操作(2 ≤ N ≤ 100 000, 1 ≤ J ≤ 100 000)。每个操作将第a个数往前或后移动b个,并询问跨越的这些数中的最大值,保证操作有效。
要求支持区间查询、增添删除,Splay是个不错的选择。
把第a个数删掉,再插到第b个数前面就好啦。有没有更有针对性的做法呢?
我是这样做的:假设把x移到y前面,x、y把一列数分为三段:a x b y c -> a b x y c
把x删除,插到y前面等价于把b和a合并。正好,为了查区间最大值,我们已经把b提取出来了。
#include <cstdio>
#include <algorithm>
const int MAX_N = 1e5, inf = 1<<30;
int N, a[MAX_N];
struct Splay {
static const int n = MAX_N+4, nil = n-1;
int ptr, &root, ch[n][2], fa[n], sz[n], v[n], mx[n];
int type(int x) { return x == ch[fa[x]][1]; }
void up(int x) { sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1; mx[x] = std::max(v[x], std::max(mx[ch[x][0]], mx[ch[x][1]])); }
void set(int x, int d, int y) { fa[ch[x][d] = y] = x; }
void rot(int x, int d)
{
int y = ch[x][d];
set(fa[x], type(x), y);
set(x, d, ch[y][d^1]);
set(y, d^1, x);
up(x);
up(y);
}
void splay(int x, int p=0)
{
int y;
while ((y = fa[x]) != p) {
int z = fa[y], t1 = type(x);
if (z != p) {
int t2 = type(y);
if (t1 == t2)
rot(z, t2), rot(y, t1);
else
rot(y, t1), rot(z, t2);
} else
rot(y, t1);
}
}
int new_node(int c)
{
ch[ptr][0] = ch[ptr][1] = nil;
sz[ptr] = 1;
v[ptr] = mx[ptr] = c;
return ptr++;
}
Splay(): ptr(1), root(ch[0][0])
{
sz[nil] = 0;
v[nil] = mx[nil] = -inf;
set(0, 0, new_node(0));
set(1, 1, new_node(0));
}
void build()
{
build(0, N-1, 2, 0);
up(2);
up(1);
}
void build(int l, int r, int p, int t)
{
if (l > r) return;
int m = (l+r)/2, x = new_node(a[m]);
set(p, t, x);
build(l, m-1, x, 0);
build(m+1, r, x, 1);
up(x);
}
void join(int x, int y, int t)
{
int p = x;
while (ch[p][t] != nil)
p = ch[p][t];
splay(p, fa[x]);
set(p, t, y);
up(p);
}
int kth(int k, int p=0)
{
int x = root;
while (x != nil) {
int s = sz[ch[x][0]];
if (k == s+1) return splay(x, p), x;
if (s >= k) x = ch[x][0];
else k -= s+1, x = ch[x][1];
}
}
int jump(int a, int b)
{
++a, ++b;
int t = a>b, x = kth(a), y = kth(b, x), z = ch[y][t], r = mx[z];
ch[y][t] = nil;
up(y);
join(ch[x][t], z, t^1);
return r;
}
} T;
int main()
{
int J;
scanf("%d %d", &N, &J);
for (int i = 0; i < N; ++i)
scanf("%d", &a[i]);
T.build();
while (J--) {
int a, b;
char o;
scanf("%d %c %d", &a, &o, &b);
printf("%d\n", T.jump(a, a+(o == 'D' ? b+1 : -b-1)));
}
return 0;
}