CF 1464 F
CF 1464 F
考虑求一个如果有交集,那么必定存在的点,这个点就是 LCA 最深的链的 \(d\) 级祖先,记它为 \(u\),其它的 \(u\) 子树内的一定没有 \(u\) 优秀,因为可能 \(u\) 子树内的点到 \(u\) 子树内的路径不合法。那么 \(u\) 子树内的路径都会是它的 \(d\) 邻居,现在就是对 \(u\) 子树外的点 check
考虑一下,如果距离 \(u\) 的距离要小于等于 \(d\),那么有两种可能,第一种是直接是 \(u\) 的祖先,还有一种可能是经过 \(u\) 的祖先然后到达 \(u\)。
现在就考虑是 \(u\) 的祖先的情况,那么那条路径必定会经过 \(u\) 的 \(d\) 级祖先 \(v\) 或者在 \(v\) 子树内,否则距离 \(u\) 的距离就大于等于 \(d\) 了。就是去查询 \(v\) 子树外是否有路径,换句话说就是查询 \(v\) 子树内是否和每个路径有交
考虑不经过 \(v\) 的情况,就是会经过 \(u\) 的祖先,然后到达它;这个就是求 \(v\) 子树内,除了 \(u\) 子树中的点中路径 LCA 到达 \(u\) 的最远值,动态直径(详见 动态直径.)维护即可,不过其实可以直接查询 \(v\) 子树内,反正 \(u\) 子树内的点必定合法,就是同时满足 \(v\) 子树外没有别的路径,\(v\) 子树内路径的 LCA 到达 \(u\) 的距离小于等于 \(d\) 就行了,求出到 \(u\) 最远的距离就行;再加上判断所有路径是否都和 \(v\) 有交就行
好像忘记写修改了
思考一下在判断中用了什么东西,所有路径中最深的 LCA,以及动态直径,用 set 插入/删除 LCA 就行了,点是否出现就在维护动态直径的线段树中加入 cnt 进行判断就行了
#include <bits/stdc++.h>
using i64 = long long;
const int N = 2E5 + 5;
int n, m;
std::vector<int> G[N];
namespace HLD {
int fa[N], dep[N], siz[N], son[N];
int dfn[N], dfn_cnt, rev[N];
int top[N];
void dfs1(int u, int FA) {
fa[u] = FA, siz[u] = 1;
dep[u] = dep[FA] + 1;
for (auto v : G[u]) {
if (v != FA) {
dfs1(v, u);
siz[u] += siz[v];
if (siz[son[u]] < siz[v]) son[u] = v;
}
}
}
void dfs2(int u, int x) {
top[u] = x;
rev[dfn[u] = ++dfn_cnt] = u;
if (son[u]) dfs2(son[u], x);
for (auto v : G[u]) {
if (v != fa[u] && v != son[u]) {
dfs2(v, v);
}
}
}
void init() {
dfs1(1, 0), dfs2(1, 1);
}
int LCA(int u, int v) {
for (; top[u] != top[v]; u = fa[top[u]]) {
if (dep[top[u]] < dep[top[v]]) std::swap(u, v);
}
return dep[u] < dep[v]? u: v;
}
int kth(int u, int k) {
if (dep[u] <= k) return 1;
for (; dep[u] - dep[top[u]] < k; u = fa[top[u]]) {
k -= (dep[u] - dep[top[u]] + 1);
}
return rev[dfn[u] - k];
}
int dis(int u, int v) {
return dep[u] + dep[v] - (dep[LCA(u, v)] << 1);
}
};
using HLD::LCA;
using HLD::kth;
using HLD::dis;
using HLD::dep;
using HLD::dfn;
using HLD::rev;
using HLD::siz;
struct BIT {
int t[N];
int lowbit(int x) {return x & -x;}
void update(int x, int val) {
for (; x <= n; x += lowbit(x)) {
t[x] += val;
}
}
int query(int u) {
int ans = 0;
for (; u; u -= lowbit(u)) {
ans += t[u];
}
return ans;
}
int query(int l, int r) {
return query(r) - query(l - 1);
}
}t1;
struct Path {
int u, v;
Path(int _u = -1, int _v = -1) : u(_u), v(_v) {}
Path operator + (const Path & x) {
Path p[6] = {*this, x, {u, x.u}, {u, x.v}, {v, x.u}, {v, x.v}};
Path ans; int mx = -1;
for (int i = 0; i < 6; i++) {
if (p[i].u == -1 || p[i].v == -1) continue;
int d = dis(p[i].u, p[i].v);
if (d > mx) {
ans = p[i], mx = d;
}
}
return ans;
}
};
struct SegmentTree {
#define ls(u) u << 1
#define rs(u) u << 1 | 1
Path s[N << 2];
int cnt[N];
void modify(int u, int l, int r, int x, int op) {
if (l == r) {
if (op == 0) s[u] = Path(-1, -1);
else s[u] = Path(rev[x], rev[x]);
return;
}
int mid = l + r >> 1;
x <= mid? modify(ls(u), l, mid, x, op): modify(rs(u), mid + 1, r, x, op);
s[u] = s[ls(u)] + s[rs(u)];
}
Path query(int u, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return s[u];
int mid = l + r >> 1;
Path ans;
if (ql <= mid) ans = query(ls(u), l, mid, ql, qr);
if (qr > mid) ans = ans + query(rs(u), mid + 1, r, ql, qr);
return ans;
}
void insert(int u) {
if (cnt[u] == 0) {
modify(1, 1, n, dfn[u], 1);
}
++cnt[u];
}
void erase(int u) {
--cnt[u];
if (cnt[u] == 0) {
modify(1, 1, n, dfn[u], 0);
}
}
#undef ls
#undef rs
}t2;
std::multiset<std::pair<int, int>> s1, s2;
bool query(int d) {
int x = s2.rbegin() -> second;
int u = kth(x, d), v = kth(u, d);
if (t1.query(dfn[v], dfn[v] + siz[v] - 1) != t1.query(n)) return false;
Path p = t2.query(1, 1, n, dfn[v], dfn[v] + siz[v] - 1);
if (std::max(dis(u, p.u), dis(u, p.v)) > d) return false;
return true;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m;
for (int i = 1; i < n; i++) {
int u, v;
std::cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
HLD::init();
for (int i = 1; i <= m; i++) {
int op;
std::cin >> op;
if (op == 1) {
int u, v;
std::cin >> u >> v;
if (u > v) std::swap(u, v);
int l = LCA(u, v);
s1.insert(std::make_pair(u, v));
s2.insert(std::make_pair(dep[l], l));
t2.insert(l);
t1.update(dfn[u], 1), t1.update(dfn[v], 1), t1.update(dfn[l], -1);
} else if (op == 2) {
int u, v;
std::cin >> u >> v;
if (u > v) std::swap(u, v);
int l = LCA(u, v);
s1.erase(s1.lower_bound(std::make_pair(u, v)));
s2.erase(s2.lower_bound(std::make_pair(dep[l], l)));
t2.erase(l);
t1.update(dfn[u], -1), t1.update(dfn[v], -1), t1.update(dfn[l], 1);
} else {
int d;
std::cin >> d;
std::cout << (query(d)? "Yes": "No") << "\n";
}
}
return 0;
}

浙公网安备 33010602011771号