我一眼以为是裸树剖,但是看完问题就知道不是那么容易了。因为只用树剖不能很好地维护操作
3
的结果。
首先,按照原树,构建出一个全部都是虚边的
我们发现,操作
1
实际上就是
这样,询问
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define p2 p << 1
#define p3 p << 1 | 1
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 = 1e5 + 5, LogN = 24;
int n, m, ecnt, nxt[N << 1], adj[N], go[N << 1], fa_s[N], lc[N], rc[N],
QAQ, fa[N][LogN], dep[N], sze[N], son[N], top[N], pos[N], idx[N], T[N << 2],
add[N << 2], ml[N];
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
}
int which(int x) {return rc[fa_s[x]] == x;}
bool is_root(int x) {
return !fa_s[x] || (lc[fa_s[x]] != x && rc[fa_s[x]] != x);
}
void upd(int x) {
ml[x] = lc[x] ? ml[lc[x]] : x;
}
void rotate(int x) {
int y = fa_s[x], z = fa_s[y], b = lc[y] == x ? rc[x] : lc[x];
if (z && !is_root(y)) (lc[z] == y ? lc[z] : rc[z]) = x;
fa_s[x] = z; fa_s[y] = x; if (b) fa_s[b] = y;
if (lc[y] == x) rc[x] = y, lc[y] = b;
else lc[x] = y, rc[y] = b; upd(y); upd(x);
}
void splay(int x) {
while (!is_root(x)) {
if (!is_root(fa_s[x])) {
if (which(x) == which(fa_s[x])) rotate(fa_s[x]);
else rotate(x);
}
rotate(x);
}
upd(x);
}
void dfs1(int u, int fu) {
int i; fa[u][0] = fu; dep[u] = dep[fu] + 1; sze[u] = 1;
for (i = 0; i <= 19; i++) fa[u][i + 1] = fa[fa[u][i]][i];
for (int e = adj[u], v; e; e = nxt[e]) {
if ((v = go[e]) == fu) continue;
dfs1(v, u); sze[u] += sze[v];
if (sze[v] > sze[son[u]]) son[u] = v;
}
}
void dfs2(int u, int fu) {
if (son[u]) {
top[son[u]] = top[u];
idx[pos[son[u]] = ++QAQ] = son[u];
dfs2(son[u], u);
}
for (int e = adj[u], v; e; e = nxt[e]) {
if ((v = go[e]) == fu || v == son[u]) continue;
top[v] = v; idx[pos[v] = ++QAQ] = v; dfs2(v, u);
}
}
void build(int l, int r, int p) {
if (l == r) return (void) (T[p] = dep[idx[l]]);
int mid = l + r >> 1;
build(l, mid, p2); build(mid + 1, r, p3);
T[p] = max(T[p2], T[p3]);
}
void down(int p) {
add[p2] += add[p]; add[p3] += add[p]; add[p] = 0;
}
void upt(int p) {
T[p] = max(T[p2] + add[p2], T[p3] + add[p3]);
}
void change(int l, int r, int s, int e, int v, int p) {
if (l == s && r == e) return (void) (add[p] += v);
int mid = l + r >> 1; down(p);
if (e <= mid) change(l, mid, s, e, v, p2);
else if (s >= mid + 1) change(mid + 1, r, s, e, v, p3);
else change(l, mid, s, mid, v, p2),
change(mid + 1, r, mid + 1, e, v, p3);
upt(p);
}
int query(int l, int r, int s, int e, int p) {
if (l == s && r == e) return T[p] + add[p];
int mid = l + r >> 1, res = 0; down(p);
if (e <= mid) res = query(l, mid, s, e, p2);
else if (s >= mid + 1) res = query(mid + 1, r, s, e, p3);
else res = max(query(l, mid, s, mid, p2),
query(mid + 1, r, mid + 1, e, p3));
upt(p); return res;
}
void init() {
int i; QAQ = top[1] = pos[1] = idx[1] = 1;
dfs1(1, 0); dfs2(1, 0); build(1, n, 1);
for (i = 1; i <= n; i++) fa_s[i] = fa[i][0], ml[i] = i;
}
void Access(int x) {
int y;
for (y = 0; x; y = x, x = fa_s[x]) {
splay(x);
if (rc[x]) change(1, n, pos[ml[rc[x]]], pos[ml[rc[x]]] +
sze[ml[rc[x]]]- 1, 1, 1);
if (y) change(1, n, pos[ml[y]], pos[ml[y]] + sze[ml[y]] - 1, -1, 1);
rc[x] = y; if (y) fa_s[y] = x;
}
}
int lca(int u, int v) {
int i; if (dep[u] < dep[v]) swap(u, v);
for (i = 20; i >= 0; i--) {
if (dep[fa[u][i]] >= dep[v]) u = fa[u][i];
if (u == v) return u;
}
for (i = 20; i >= 0; i--) if (fa[u][i] != fa[v][i])
u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
int path_query(int u, int v) {
int w = lca(u, v), res;
res = query(1, n, pos[u], pos[u], 1) +
query(1, n, pos[v], pos[v], 1);
return res - (query(1, n, pos[w], pos[w], 1) << 1) + 1;
}
int main() {
int i, op, x, y; n = read(); m = read();
for (i = 1; i < n; i++) {
x = read(); y = read();
add_edge(x, y); add_edge(y, x);
}
init(); while (m--) {
op = read(); x = read();
if (op == 1) Access(x);
else if (op == 2) y = read(), printf("%d\n", path_query(x, y));
else printf("%d\n", query(1, n, pos[x], pos[x] + sze[x] - 1, 1));
}
return 0;
}