[CF1464F] My Beautiful Madness
[题目链接]
http://codeforces.com/contest/1464/problem/F
[题解]
判断一个集合是复杂的 , 考虑如何选择一个点 , 只需判断这个点是否满足条件即可。
结论 : 此点为深度最大的 \(LCA\) 的 \(d\) 级祖先 \(u\) 。
显然子树内的路径满足条件。
下面只需考虑子树外的。
不妨求出 \(u\) 的 \(d\) 级祖先 \(v\) , 显然所有路径要么在 \(v\) 的子树内 , 要么穿过 \(v\)。
求出树的 \(DFS\) 序 , 树上差分 + 线段树维护路径数量。
由于离一个点最远的点必然是直径的两个端点之一 , 故线段树维护直径 , 找出 \(v\) 子树中离 \(u\) 最远的点 , 判断与 \(x\) 的大小关系即可。
时间复杂度 : \(O(NlogN)\)
[代码]
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i , l , r) for (int i = (l); i < (r); ++i)
typedef pair < int , int > pii;
const int MN = 4e5 + 5 , LOG = 20;
int N , Q , o[MN] , id[MN] , eid[MN] , dfn , dep[MN] , cnt[MN];
vector < int > g[MN];
int ID[MN] , lg[MN << 1] , tot , st[MN << 1][LOG] , up[MN][LOG] , fa[MN];
inline void dfs(int u) {
o[id[u] = ++dfn] = u; st[ID[u] = ++tot][0] = u;
up[u][0] = fa[u];
for (int i = 1; i < LOG; ++i) up[u][i] = up[up[u][i - 1]][i - 1];
for (int v : g[u]) if (v != fa[u]) {
fa[v] = u , dep[v] = dep[u] + 1;
dfs(v) , st[++tot][0] = u;
}
eid[u] = dfn;
}
inline int cmp(int x, int y) {return dep[x] > dep[y] ? y : x;}
inline void build(int n) {
for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
for (int k = 1; k < LOG; ++k)
for (int i = 1; i <= n - (1 << k) + 1; ++i)
st[i][k] = cmp(st[i][k - 1], st[i + (1 << k - 1)][k - 1]);
}
inline int LCA(int u, int v) {
if (id[u] > id[v]) swap(u, v);
u = ID[u], v = ID[v]; int t = lg[v - u + 1];
return cmp(st[u][t], st[v - (1 << t) + 1][t]);
}
inline int dist(int u , int v) {
return (u && v) ? dep[u] + dep[v] - 2 * dep[LCA(u, v)] : -1;
}
inline int jump(int u , int d) {
if (dep[u] <= d) return 1;
for (; d; d &= d - 1) u = up[u][__builtin_ctz(d)];
return u;
}
struct BIT {
int sum[MN];
inline void add(int x, int y) {for (; x <= N; x += x & -x) sum[x] += y;}
inline int query(int x) {int res = 0; for (; x; x -= x & -x) res += sum[x]; return res;}
inline int query(int l, int r) { return query(r) - query(l - 1);}
} tr;
struct node {
int x, y, z;
node(int _x = 0, int _y = 0) {x = _x, y = _y, z = dist(x, y);}
inline friend bool operator < (const node &A, const node &B) { return A.z < B.z; }
inline friend node operator ^ (const node &A, const node &B) { return std::max({A, B, node(A.x, B.x), node(A.x, B.y), node(A.y, B.x), node(A.y, B.y)});}
} diam[MN << 2];
void modify(int p, int l, int r, int pos, bool tp) {
if (l == r) return void(diam[p] = node(tp * o[pos], tp * o[pos]));
int mid = l + r >> 1; mid >= pos ? modify(p << 1, l, mid, pos, tp) : modify(p << 1 | 1, mid + 1, r, pos, tp);
diam[p] = diam[p << 1] ^ diam[p << 1 | 1];
}
node query(int p, int l, int r, int L, int R) {
if (l >= L && r <= R) return diam[p];
int mid = l + r >> 1;
if (mid >= L && mid < R) return query(p << 1, l, mid, L, R) ^ query(p << 1 | 1, mid + 1, r, L, R);
if (mid >= L) return query(p << 1, l, mid, L, R);
return query(p << 1 | 1, mid + 1, r, L, R);
}
set < pii > S;
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);
}
dfs(1) , build(tot);
for (int i = 1 , op , x , y , c = 0; i <= Q; ++i) {
scanf("%d%d" , &op , &x);
if (op == 3) {
int v = jump(S.rbegin()->second, x), v1 = jump(v, x);
if (tr.query(id[v1], eid[v1]) != c) {puts("No"); continue;}
node tmp = query(1 , 1 , N , id[v1] , eid[v1]);
puts(std::max(dist(tmp.x, v), dist(tmp.y, v)) > x ? "No" : "Yes");
} else {
scanf("%d", &y); int z = LCA(x, y);
if (op == 1) {
++c; if (!cnt[z]++) S.insert({dep[z], z}), modify(1, 1, N, id[z], 1);
tr.add(id[x], 1), tr.add(id[y], 1), tr.add(id[z], -1);
} else {
--c; if (!--cnt[z]) S.erase({dep[z], z}), modify(1, 1, N, id[z], 0);
tr.add(id[x], -1), tr.add(id[y], -1), tr.add(id[z], 1);
}
}
}
return 0;
}