手动模拟,可以发现:单旋最小值或最大值到根,实际上就是删掉了2条边又加上了
而对于维护深度,由于根节点不断变化,所以树中所有节点的深度也在不断地整体变化。因此考虑用一个LCT维护这棵树,这样查询一个节点的深度,就是查询一个点到根的距离。同时又能支持动态加边和删边。
所以,现在就剩下一个问题:如何确定新节点的位置。
以下,设x为待插入的节点,
假设节点x应该作为节点
从
简单地说,节点y在其后继节点(下面记为
这时候,如果节点x作为了节点
对于节点x作为其他节点的左子节点,也是同理。所以,得出结论:
新插入的节点,一定是这个节点在树中的前驱的右子节点,或者后继的左子节点。
同时,也可以得到,对于任意一个关键码
所以,用一个set维护数集,就能较方便地找到插入位置了。
代码:
#include <set>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 4e5 + 5;
int n, T, fa[N], lc[N], rc[N], sze[N], rev[N], len, que[N], val[N],
L[N], R[N], F[N], Root, ans;
struct cyx {
int id;
cyx() {}
cyx(int _id) : id(_id) {}
friend inline bool operator == (const cyx &a, const cyx &b) {
return a.id == b.id;
}
friend inline bool operator < (const cyx &a, const cyx &b) {
return val[a.id] < val[b.id];
}
friend inline bool operator > (const cyx &a, const cyx &b) {
return val[a.id] > val[b.id];
}
friend inline bool operator <= (const cyx &a, const cyx &b) {
return val[a.id] <= val[b.id];
}
friend inline bool operator >= (const cyx &a, const cyx &b) {
return val[a.id] >= val[b.id];
}
};
set<cyx> orz;
set<cyx>::iterator pyz;
int which(int x) {return rc[fa[x]] == x;}
bool is_root(int x) {
return !fa[x] || (lc[fa[x]] != x && rc[fa[x]] != x);
}
void down(int x) {
if (rev[x]) {
swap(lc[x], rc[x]);
if (lc[x]) rev[lc[x]] ^= 1;
if (rc[x]) rev[rc[x]] ^= 1;
rev[x] = 0;
}
}
void upt(int x) {
sze[x] = 1;
if (lc[x]) sze[x] += sze[lc[x]];
if (rc[x]) sze[x] += sze[rc[x]];
}
void rotate(int x) {
int y = fa[x], z = fa[y], b = lc[y] == x ? rc[x] : lc[x];
if (z && !is_root(y)) (lc[z] == y ? lc[z] : rc[z]) = x;
fa[x] = z; fa[y] = x; if (b) fa[b] = y;
if (lc[y] == x) rc[x] = y, lc[y] = b;
else lc[x] = y, rc[y] = b; upt(y); upt(x);
}
void splay(int x) {
int i, y; que[len = 1] = x;
for (y = x; !is_root(y); y = fa[y]) que[++len] = fa[y];
for (i = len; i; i--) down(que[i]);
while (!is_root(x)) {
if (!is_root(fa[x])) {
if (which(x) == which(fa[x])) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
}
void Access(int x) {
int y; for (y = 0; x; y = x, x = fa[x]) {
splay(x); rc[x] = y;
if (y) fa[y] = x; upt(x);
}
}
void MakeRoot(int x) {
Access(x); splay(x); rev[x] ^= 1;
}
void Link(int x, int y) {
MakeRoot(x); fa[x] = y;
}
void Cut(int x, int y) {
MakeRoot(x); Access(y); splay(y);
lc[y] = fa[x] = 0; upt(y);
}
int Query(int x, int y) {
MakeRoot(x); Access(y); splay(y);
return sze[y];
}
void splayMin() {
pyz = orz.begin(); int x = pyz->id, y = R[x], z = F[x];
ans = Query(Root, x); if (x == Root) return;
if (y) Cut(x, y); Cut(x, z); if (y) Link(z, y);
Link(x, Root); F[R[x] = Root] = x; F[Root = x] = 0;
L[z] = y; if (y) F[y] = z;
}
void splayMax() {
pyz = orz.end(); int x = (*--pyz).id, y = L[x], z = F[x];
ans = Query(Root, x); if (x == Root) return;
if (y) Cut(x, y); Cut(x, z); if (y) Link(z, y);
Link(x, Root); F[L[x] = Root] = x; F[Root = x] = 0;
R[z] = y; if (y) F[y] = z;
}
int pre(cyx x) {
pyz = orz.find(x);
return pyz == orz.begin() ? 0 : (*--pyz).id;
}
int suf(cyx x) {
pyz = orz.find(x);
return ++pyz == orz.end() ? 0 : pyz->id;
}
int main() {
int i, op; n = read();
for (i = 1; i <= n; i++) sze[i] = 1; while (n--) {
op = read(); if (op == 1) {
val[++T] = read(); orz.insert(cyx(T));
if (!Root) {Root = T; printf("1\n"); continue;}
int p = pre(cyx(T)), s = suf(cyx(T));
if (p && !R[p]) F[R[p] = T] = p, Link(p, T);
if (s && !L[s]) F[L[s] = T] = s, Link(s, T);
ans = Query(Root, T);
}
else if (op == 2) splayMin();
else if (op == 3) splayMax();
else if (op == 4) {
splayMin(); pyz = orz.begin(); orz.erase(pyz);
if (!L[Root] && !R[Root]) {Root = 0; continue;}
Cut(Root, R[Root]); Root = R[Root]; F[Root] = 0;
}
else {
splayMax(); pyz = orz.end(); orz.erase(--pyz);
if (!L[Root] && !R[Root]) {Root = 0; continue;}
Cut(Root, L[Root]); Root = L[Root]; F[Root] = 0;
}
printf("%d\n", ans);
}
return 0;
}