序列终结者
Description
BZOJ1251
Luogu4146
维护一个序列,支持区间加,区间翻转,区间取最大值这三个操作。
Solution
Splay.
就是细节比较麻烦。
Code
#include <cstdio>
#include <algorithm>
const int N = 50000 + 10;
int fa[N], ch[N][2], val[N], sz[N], rev[N], add[N], mx[N];
void upd(int x) {
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
mx[x] = std::max(val[x], std::max(mx[ch[x][0]], mx[ch[x][1]]));
}
void pd(int x) {
if (rev[x]) {
std::swap(ch[x][0], ch[x][1]);
rev[ch[x][0]] ^= 1;
rev[ch[x][1]] ^= 1;
rev[x] = 0;
}
if (add[x]) {
if (ch[x][0]) val[ch[x][0]] += add[x], add[ch[x][0]] += add[x], mx[ch[x][0]] += add[x];
if (ch[x][1]) val[ch[x][1]] += add[x], add[ch[x][1]] += add[x], mx[ch[x][1]] += add[x];
add[x] = 0;
}
}
int dir(int x) { return x == ch[fa[x]][1]; }
void rot(int x) {
int f = fa[x], d = dir(x);
if (fa[x] = fa[f]) ch[fa[x]][dir(f)] = x;
if (ch[f][d] = ch[x][d^1]) fa[ch[f][d]] = f;
ch[fa[f] = x][d^1] = f;
upd(f);
upd(x);
}
int st[N];
void splay(int x, int t = 0) {
int top = 0, i;
for (i = x; fa[i]; i = fa[i]) st[top++] = fa[i];
while (top--) pd(st[top]);
pd(x);
for (; fa[x] != t; rot(x)) if (fa[fa[x]] != t) rot(dir(fa[x]) == dir(x) ? fa[x] : x);
}
int kth(int k, int t) {
int o = t;
while (1) {
pd(o);
if (sz[ch[o][0]] == k-1) break;
else if (sz[ch[o][0]] >= k) o = ch[o][0];
else { k -= sz[ch[o][0]] + 1; o = ch[o][1]; }
}
splay(o, fa[t]);
return o;
}
int n;
void reverse(int l, int r) {
splay(1);
int y = kth(r+1, 1);
int x = ch[y][0];
kth(l-1, x);
rev[ch[ch[y][0]][1]] ^= 1;
}
void addval(int l, int r, int k) {
splay(1);
int y = kth(r+1, 1);
int x = ch[y][0];
kth(l-1, x);
add[ch[ch[y][0]][1]] += k;
val[ch[ch[y][0]][1]] += k;
mx[ch[ch[y][0]][1]] += k;
}
int query(int l, int r) {
splay(1);
int y = kth(r+1, 1);
int x = ch[y][0];
kth(l-1, x);
return mx[ch[ch[y][0]][1]];
}
void put(int o) {
if (!o) return;
put(ch[o][0]);
printf("%d %d %d\n", ch[o][0], ch[o][1], val[o]);
put(ch[o][1]);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n+2; ++i) {
if (fa[i] = i-1) ch[i-1][1] = i;
sz[i] = n - i + 3;
val[i] = 0;
}
mx[0] = -2147483647;
val[n+1] = 0;
int m, l, r, v, op;
scanf("%d", &m);
while (m--) {
scanf("%d%d%d", &op, &l, &r);
if (op == 1) { scanf("%d", &v); addval(l+1, r+1, v); }
else if (op == 2) reverse(l+1, r+1);
else printf("%d\n", query(l+1, r+1));
}
return 0;
}
Note
如果不是非常必要的话,还是不要使用平衡树了,实在是有点难调,也没有线段树直观。