#if __INCLUDE_LEVEL__ == 0 #include __BASE_FILE__ void Solve() { int n; IN(n); HldTree g(n); for (int _ : Rep(0, n - 1)) { int i, j; IN(OneBased(i, j)); g.add_edge({i, j, 1}); } g.build(0); set se; atcoder::fenwick_tree f(n); auto modify = [&](int t1, int t2, int sign) { int i = g.order[t1]; int j = g.order[t2]; f.add(t1, sign * g.d(i, j)); }; auto add = [&](int i) { int t = g.in[i]; assert(!se.contains(t)); auto it = se.lower_bound(t); if (it != se.begin() && it != se.end()) { modify(*prev(it), *it, -1); } if (it != se.begin()) { modify(*prev(it), t, 1); } if (it != se.end()) { modify(t, *it, 1); } se.insert(it, t); }; auto rm = [&](int i) { int t = g.in[i]; assert(se.contains(t)); auto it = se.lower_bound(t); it = se.erase(it); if (it != se.begin()) { modify(*prev(it), t, -1); } if (it != se.end()) { modify(t, *it, -1); } if (it != se.begin() && it != se.end()) { modify(*prev(it), *it, 1); } }; for (int i : Rep(0, n)) { int c; IN(c); if (c == 1) { add(i); } } auto go = [&](vector> v) -> int { { vector> nv; for (const auto& [l, r] : v) { auto it = se.lower_bound(l); if (it != se.end() && *it < r) { nv.emplace_back(l, r); } } v = move(nv); } if (v.empty()) { return 0; } int ret = 0; auto [pl, pr] = v.back(); for (const auto& [l, r] : v) { auto it = prev(se.lower_bound(pr)); ret += g.d(g.order[*it], g.order[*se.lower_bound(l)]); ret += f.sum(l, *prev(se.lower_bound(r))); pl = l; pr = r; } assert(ret % 2 == 0); ret >>= 1; return ret + 1; }; int q; IN(q); while (q--) { int tp; IN(tp); if (tp == 1) { int i; IN(OneBased(i)); if (se.contains(g.in[i])) { rm(i); } else { add(i); } } else { int x, y; IN(OneBased(x, y)); int ans; if (x == y) { ans = go({{0, n}}); } else { if (g.is_ancestor(y, x)) { int z = g.next(y, x); ans = go({{0, g.in[z]}, {g.out[z], n}}); } else { ans = go({{g.in[y], g.out[y]}}); } } OUT(ans); } } } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); Solve(); } #elif __INCLUDE_LEVEL__ == 1 #include #include struct Graph { struct Edge { int src, dst; int64_t cost; int other(int v) const { __glibcxx_assert(v == src or v == dst); return src ^ dst ^ v; } }; std::vector edges; std::vector>> adj; Graph() {} explicit Graph(int n) : adj(n) {} int n() const { return std::size(adj); } int m() const { return std::size(edges); } int add_edge(const Edge& e, bool directed) { __glibcxx_assert(0 <= e.src and e.src < n()); __glibcxx_assert(0 <= e.dst and e.dst < n()); int id = m(); edges.push_back(e); adj[e.src].emplace_back(e.dst, id); if (not directed) adj[e.dst].emplace_back(e.src, id); return id; } }; struct DfsTree : Graph { using T = decltype(Edge::cost); std::vector root; std::vector pv; std::vector pe; std::vector order; std::vector in; std::vector out; std::vector sub; std::vector depth; std::vector min_depth; std::vector dist; std::vector last; int num_trials; DfsTree() {} explicit DfsTree(int n) : Graph(n), root(n, -1), pv(n, -1), pe(n, -1), in(n, -1), out(n, -1), sub(n, -1), depth(n, -1), min_depth(n, -1), dist(n, std::numeric_limits::max()), last(n, -1), num_trials(0) {} int add_edge(const Edge& e) { return Graph::add_edge(e, false); } void dfs(int r, bool clear_order = true) { __glibcxx_assert(0 <= r and r < n()); root[r] = r; pv[r] = -1; pe[r] = -1; if (clear_order) order.clear(); depth[r] = 0; dist[r] = T{}; dfs_impl(r); ++num_trials; } void dfs_all() { std::fill(std::begin(root), std::end(root), -1); for (int v = 0; v < n(); ++v) if (root[v] == -1) dfs(v, v == 0); } int deeper(int id) const { __glibcxx_assert(0 <= id and id < m()); int a = edges[id].src; int b = edges[id].dst; return depth[a] < depth[b] ? b : a; } bool is_tree_edge(int id) const { __glibcxx_assert(0 <= id and id < m()); return id == pe[deeper(id)]; } bool is_ancestor(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); return in[u] <= in[v] and out[v] <= out[u]; } private: void dfs_impl(int v) { in[v] = std::size(order); order.push_back(v); sub[v] = 1; min_depth[v] = depth[v]; last[v] = num_trials; for (auto&& [u, id] : adj[v]) { if (id == pe[v]) continue; if (last[u] == num_trials) { min_depth[v] = std::min(min_depth[v], depth[u]); continue; } root[u] = root[v]; pv[u] = v; pe[u] = id; depth[u] = depth[v] + 1; dist[u] = dist[v] + edges[id].cost; dfs_impl(u); sub[v] += sub[u]; min_depth[v] = std::min(min_depth[v], min_depth[u]); } out[v] = std::size(order); } }; struct HldTree : DfsTree { std::vector head; HldTree() {} explicit HldTree(int n) : DfsTree(n), head(n, -1) {} void build(int r, bool clear_order = true) { __glibcxx_assert(0 <= r and r < n()); dfs(r, clear_order); order.erase(std::end(order) - sub[r], std::end(order)); head[r] = r; build_impl(r); } void build_all() { std::fill(std::begin(root), std::end(root), -1); for (int v = 0; v < n(); ++v) if (root[v] == -1) build(v, v == 0); } int lca(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); while (true) { if (in[u] > in[v]) std::swap(u, v); if (head[u] == head[v]) return u; v = pv[head[v]]; } } int d(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); return depth[u] + depth[v] - 2 * depth[lca(u, v)]; } T distance(int u, int v) const { __glibcxx_assert(0 <= u and u < n()); __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(root[u] == root[v]); return dist[u] + dist[v] - 2 * dist[lca(u, v)]; } int la(int v, int d) const { __glibcxx_assert(0 <= v and v < n()); __glibcxx_assert(0 <= d and d <= depth[v]); while (depth[head[v]] > d) v = pv[head[v]]; return order[in[head[v]] + (d - depth[head[v]])]; } int next(int src, int dst) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); __glibcxx_assert(src != dst); if (not is_ancestor(src, dst)) return pv[src]; return la(dst, depth[src] + 1); } int next(int src, int dst, int k) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); __glibcxx_assert(k >= 0); int v = lca(src, dst); if (k <= depth[src] - depth[v]) return la(src, depth[src] - k); k -= depth[src] - depth[v]; __glibcxx_assert(k <= depth[dst] - depth[v]); return la(dst, depth[v] + k); } template void apply(int src, int dst, bool vertex, Function f) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); int v = lca(src, dst); while (head[src] != head[v]) { f(in[src] + 1, in[head[src]]); src = pv[head[src]]; } if (vertex) f(in[src] + 1, in[v]); else if (src != v) f(in[src] + 1, in[v] + 1); auto rec = [&](auto self, int to) -> void { if (head[v] == head[to]) { if (v != to) f(in[v] + 1, in[to] + 1); return; } self(self, pv[head[to]]); f(in[head[to]], in[to] + 1); }; rec(rec, dst); } template int search(int src, int dst, bool vertex, Searcher f) const { __glibcxx_assert(0 <= src and src < n()); __glibcxx_assert(0 <= dst and dst < n()); __glibcxx_assert(root[src] == root[dst]); int res = -1; apply(src, dst, vertex, [&](int l, int r) { if (res != -1) return; int i = f(l, r); if (l > r) std::swap(l, r); if (l <= i and i < r) res = vertex ? order[i] : pe[order[i]]; }); return res; } private: void build_impl(int v) { in[v] = std::size(order); order.push_back(v); auto pos = std::partition(std::begin(adj[v]), std::end(adj[v]), [&](auto&& e) { return e.second == pe[e.first]; }); auto it = std::max_element(std::begin(adj[v]), pos, [&](auto&& a, auto&& b) { return sub[a.first] < sub[b.first]; }); if (it != std::begin(adj[v])) std::iter_swap(std::begin(adj[v]), it); std::partition(pos, std::end(adj[v]), [&](auto&& e) { return e.second == pe[v]; }); for (auto&& [u, id] : adj[v]) { if (id != pe[u]) break; head[u] = u == adj[v].front().first ? head[v] : u; build_impl(u); } out[v] = std::size(order); } }; template concept MyRange = std::ranges::range && !std::convertible_to && !std::convertible_to; template concept MyTuple = std::__is_tuple_like::value && !MyRange; namespace std { istream& operator>>(istream& is, MyRange auto&& r) { for (auto&& e : r) { is >> e; } return is; } istream& operator>>(istream& is, MyTuple auto&& t) { apply([&](auto&... xs) { (is >> ... >> xs); }, t); return is; } ostream& operator<<(ostream& os, MyRange auto&& r) { auto sep = ""; for (auto&& e : r) { os << exchange(sep, " ") << forward(e); } return os; } ostream& operator<<(ostream& os, MyTuple auto&& t) { auto sep = ""; apply([&](auto&... xs) { ((os << exchange(sep, " ") << xs), ...); }, t); return os; } } // namespace std template class OneBased { public: explicit OneBased(T&& x) : ref_(std::forward(x)) {} template requires(sizeof...(Ts) > 1) OneBased(Ts&&... xs) : ref_(std::forward_as_tuple(std::forward(xs)...)) {} friend std::istream& operator>>(std::istream& is, OneBased x) { if constexpr (MyRange) { for (auto&& e : x.ref_) { is >> ::OneBased(e); } } else if constexpr (MyTuple) { std::apply([&](auto&... xs) { (is >> ... >> ::OneBased(xs)); }, x.ref_); } else { is >> x.ref_; --x.ref_; } return is; } friend std::ostream& operator<<(std::ostream& os, OneBased x) { if constexpr (MyRange) { auto f = [](auto&& e) { return ::OneBased(std::forward(e)); }; os << (x.ref_ | std::views::transform(f)); } else if constexpr (MyTuple) { std::apply([&](auto&... xs) { os << std::tuple(::OneBased(xs)...); }, x.ref_); } else { os << ++x.ref_; --x.ref_; } return os; } private: T ref_; }; template OneBased(T&&) -> OneBased; template OneBased(Ts&&...) -> OneBased>; using namespace std; #define _ _ [[maybe_unused]] #define Rep(...) [](int l, int r) { return views::iota(min(l, r), r); }(__VA_ARGS__) #define IN(...) (cin >> forward_as_tuple(__VA_ARGS__)) #define OUT(...) (cout << forward_as_tuple(__VA_ARGS__) << '\n') #endif // __INCLUDE_LEVEL__ == 1