我怎么又胡错简单题了 /ll。
书接上回。
- 给出
n 个点的树。初始所有点都是白色,你要支持q 次操作:
1 u:翻转u 的颜色。2 u v:记当前黑点集合为S ,求\min\limits_{x\in S}(\text{dis}(u,x)+\text{dis}(x,v)) 。
你谷首杀。
题中还保证了只会 1 u 只会操作叶子结点,但是我感觉这个条件没什么用。应该只是为了契合原题意。
以
显然只需要最小化括号里的式子。注意到这个 LCA 不是很好处理,所以最暴力的想法是考虑枚举
不妨认为
Case 1:
在这种情况下,
若
否则对于
Case 2:
我一开始以为这种情况下同样有
如果
当
否则就会满足
如果
Case 3:
此时
类似 Case 1,对于重链底端结点单独用线段树求出限制区域内黑点深度最小值。对于剩余的情况维护
接下来考虑带上修改,你发现对于
时间复杂度
#include <bits/stdc++.h>
using namespace std; const int N = 200005, I = 5e8; vector<int> g[N];
int n, q, d[N], s[N], h[N], t[N], df[N], id, f[N], rv[N]; bool c[N];
struct SGT {
int a[N << 2];
int ls(int x) { return x << 1; } int rs(int x) { return x << 1 | 1; }
void B(int x, int l, int r) {
a[x] = I; if (l == r) return; int m = l + r >> 1;
B(ls(x), l, m); B(rs(x), m + 1, r);
}
void U(int x, int l, int r, int k, int v) {
if (l == r) return void(a[x] = v); int m = l + r >> 1;
if (k <= m) U(ls(x), l, m, k, v); else U(rs(x), m + 1, r, k, v);
a[x] = min(a[ls(x)], a[rs(x)]);
}
void U(int k, int v) { U(1, 1, n, k, v); }
int Q(int x, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return a[x]; int m = l + r >> 1, t = I;
if (ql <= m) t = Q(ls(x), l, m, ql, qr);
if (qr > m) t = min(t, Q(rs(x), m + 1, r, ql, qr)); return t;
}
int Q(int l, int r) { return l > r ? I : Q(1, 1, n, l, r); }
} t1, t2, t3;
void d1(int u) {
s[u] = 1;
for (int v : g[u])
if (v != f[u]) {
d[v] = d[u] + 1; f[v] = u; d1(v);
s[u] += s[v]; if (s[h[u]] < s[v]) h[u] = v;
}
}
void d2(int u, int p) {
t[u] = p; df[u] = ++id; rv[id] = u; if (h[u]) d2(h[u], p);
for (int v : g[u]) if (v != f[u] && v != h[u]) d2(v, v);
}
int lca(int x, int y) {
for (; t[x] != t[y]; x = f[t[x]]) if (d[t[x]] < d[t[y]]) swap(x, y);
return d[x] < d[y] ? x : y;
}
void rmk(int x) {
int k = (h[x] ? min(t1.Q(df[x], df[h[x]] - 1),
t1.Q(df[h[x]] + s[h[x]], df[x] + s[x] - 1))
: t1.Q(df[x], df[x] + s[x] - 1));
t2.U(df[x], k - d[x]); t3.U(df[x], k - (d[x] << 1));
}
void U(int x) {
t1.U(df[x], c[x] ? I : d[x]); c[x] ^= 1; rmk(x);
for (; f[t[x]]; x = f[t[x]]) rmk(f[t[x]]);
}
int Q(int x, int y) {
if (d[x] < d[y]) swap(x, y); int a = lca(x, y), k;
auto F = [&](int v) {
int r = t1.Q(df[v], df[v] + s[v] - 1) - d[v];
for (;; v = f[t[v]]) {
if (t[v] == t[a])
return make_pair(rv[df[a] + 1],
min(r, t2.Q(df[a] + 1, df[v] - 1)) - d[a]);
r = min(r, t2.Q(df[t[v]], df[v] - 1));
if (f[t[v]] != a)
r = min({r, min(t1.Q(df[f[t[v]]], df[t[v]] - 1),
t1.Q(df[t[v]] + s[t[v]],
df[f[t[v]]] + s[f[t[v]]] - 1)) -
d[f[t[v]]]});
else return make_pair(t[v], r - d[a]);
}
};
auto [i, j] = F(x); k = j;
if (y != a) {
auto [z, w] = F(y); k = min(k, w); if (df[i] > df[z]) swap(i, z);
k = min(k, min({t1.Q(df[a], df[i] - 1),
t1.Q(df[i] + s[i], df[z] - 1),
t1.Q(df[z] + s[z], df[a] + s[a] - 1)}) - (d[a] << 1));
} else k = min(k, min(t1.Q(df[a], df[i] - 1),
t1.Q(df[i] + s[i], df[a] + s[a] - 1)) - (d[a] << 1));
if (f[a]) k = min(k, min(t1.Q(df[a] + s[a], df[f[a]] + s[f[a]] - 1),
t1.Q(df[f[a]], df[a] - 1)) - (d[f[a]] << 1));
for (a = f[a]; a; a = f[t[a]]) {
k = min(k, t3.Q(df[t[a]], df[a] - 1));
if (f[t[a]])
k = min(k, min(t1.Q(df[f[t[a]]], df[t[a]] - 1),
t1.Q(df[t[a]] + s[t[a]],
df[f[t[a]]] + s[f[t[a]]] - 1)) -
(d[f[t[a]]] << 1));
}
return k > N ? -1 : (k << 1) + d[x] + d[y];
}
int main() {
scanf("%d%d", &n, &q);
for (int i = 1, u, v; i < n; ++i)
scanf("%d%d", &u, &v), g[u].emplace_back(v), g[v].emplace_back(u);
d1(1); d2(1, 1); t1.B(1, 1, n); t2.B(1, 1, n); t3.B(1, 1, n);
for (int o, x, y; q--;) {
cin >> o >> x; if (o & 1) U(x); else cin >> y, printf("%d\n", Q(x, y));
}
return 0;
}