因为不能直接打spaly,所以我们先手动模拟一次,找找性质。
题目说的很明白,旋转的必须是最小的或者最大的。举最小的为例,它旋转到根节点并不会破坏原来的结构,而是将自己的右儿子变为父亲的左儿子,然后认根节点为右儿子,自己成为根节点,那么这个旋转只需要O(1)。
对于插入操作,直觉告诉我会和前驱后继有关,后面发现真的是找前驱后继中深度大的那个点认父亲。
删除的话就是旋转以后直接删除。
还有维护深度,我们发现每次修改都是区间修改,所以对关键值离散化以后用线段树处理(不用管没出现的值),前驱后继就用stl的set。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <set>
#define ls tr[x].son[0]
#define rs tr[x].son[1]
#define lc p << 1
#define rc p << 1 | 1
#define mid (t[p].l + t[p].r) / 2
using namespace std;
const int N = 1e5 + 10, inf = 1e8;
struct node { int f, son[2]; } tr[N]; int root;
struct SetmentTree {
int l, r, c;
} t[N << 2];
set<int> s;
set<int>::iterator it;
struct query { int op, x; } a[N]; int cnt, b[N];
int ans;
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r, t[p].c = 0;
if (l == r) return;
build(lc, l, mid);
build(rc, mid + 1, r);
}
void change(int p, int l, int r, int k) {
if (l <= t[p].l && t[p].r <= r) {
t[p].c += k;
return;
}
if (l <= mid) change(lc, l, r, k);
if (mid < r) change(rc, l, r, k);
}
int calc(int p, int x) {
if (t[p].l == t[p].r)
return t[p].c;
if (x <= mid) return t[p].c + calc(lc, x);
else return t[p].c + calc(rc, x);
}
void opt1(int x) {
it = s.lower_bound(x);
int r = *it, l = *--it;
s.insert(x);
int dep;
if (l == -inf && r == inf) {
dep = 0;
root = x;
}
else if (l != -inf && r == inf) {
dep = calc(1, l);
tr[x].f = l; tr[l].son[1] = x;
}
else if (l == -inf && r != inf) {
dep = calc(1, r);
tr[x].f = r, tr[r].son[0] = x;
}
else {
int p1 = calc(1, l), p2 = calc(1, r);
if (p1 > p2) dep = p1, tr[x].f = l, tr[l].son[1] = x;
else dep = p2, tr[x].f = r, tr[r].son[0] = x;
}
dep++;
ans += dep;
dep -= calc(1, x);
change(1, x, x, dep);
}
void opt2() {
int x = *++s.begin();
int tt = calc(1, x);
ans += tt;
if (x != root) {
int f = tr[x].f;
change(1, f, *--(--s.end()), 1);
change(1, x, x, 1 - tt);
tr[f].son[0] = rs;
if (rs) tr[rs].f = f;
tr[x].son[1] = root;
tr[root].f = x;
tr[x].f = 0;
root = x;
}
}
void opt3() {
int x = *--(--s.end());
int tt = calc(1, x);
ans += tt;
if (x != root) {
int f = tr[x].f;
change(1, *++s.begin(), f, 1);
change(1, x, x, 1 - tt);
tr[f].son[1] = ls;
if (ls) tr[ls].f = f;
tr[x].son[0] = root;
tr[root].f = x;
tr[x].f = 0;
root = x;
}
}
void opt4() {
opt2();
s.erase(root);
root = tr[root].son[1];
tr[root].f = 0;
change(1, *++s.begin(), *--(--s.end()), -1);
}
void opt5() {
opt3();
s.erase(root);
root = tr[root].son[0];
tr[root].f = 0;
change(1, *++s.begin(), *--(--s.end()), -1);
}
int main() {
int m; cin >> m;
build(1, 1, m);
for (int i = 1; i <= m; i++) {
scanf("%d", &a[i].op);
if (a[i].op == 1) {
scanf("%d", &a[i].x);
b[++cnt] = a[i].x;
}
}
sort(b + 1, b + cnt + 1);
cnt = unique(b + 1, b + cnt + 1) - b - 1;
s.insert(-inf), s.insert(inf);
for (int i = 1; i <= m; i++) {
ans = 0;
if (a[i].op == 1) opt1(a[i].x = lower_bound(b + 1, b + cnt + 1, a[i].x) - b);
else if (a[i].op == 2) opt2();
else if (a[i].op == 3) opt3();
else if (a[i].op == 4) opt4();
else opt5();
printf("%d\n", ans);
}
return 0;
}