// #define PROBLEM "https://yukicoder.me/problems/no/3189" #define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/1/ITP1_1_A" #include #include namespace zawa { using i16 = std::int16_t; using i32 = std::int32_t; using i64 = std::int64_t; using i128 = __int128_t; using u8 = std::uint8_t; using u16 = std::uint16_t; using u32 = std::uint32_t; using u64 = std::uint64_t; using usize = std::size_t; } // namespace zawa #include #include #include #include #include #include #include namespace zawa { template class HeavyLightDecomposition { public: static constexpr V Invalid() noexcept { return INVALID; } HeavyLightDecomposition() = default; HeavyLightDecomposition(std::vector> T, V root = 0u) : m_n{T.size()}, m_par(m_n), m_top(m_n), m_idx(m_n), m_inv(m_n), m_bottom(m_n), m_size(m_n, usize{1}), m_dep(m_n) { auto dfs1 = [&](auto dfs, V v, V p, usize d) -> usize { m_par[v] = p; m_dep[v] = d; if (p != INVALID) { for (usize i = 0 ; i + 1 < T[v].size() ; i++) if (T[v][i] == p) { std::swap(T[v][i], T[v].back()); break; } assert(T[v].back() == p); T[v].pop_back(); } for (V x : T[v]) m_size[v] += dfs(dfs, x, v, d + 1); for (usize i = 1 ; i < T[v].size() ; i++) if (m_size[T[v][0]] < m_size[T[v][i]]) std::swap(T[v][0], T[v][i]); return m_size[v]; }; auto dfs2 = [&](auto dfs, V v, V idx, V top) -> V { m_idx[v] = idx++; m_inv[m_idx[v]] = v; m_top[v] = top; if (T[v].size()) { idx = dfs(dfs, T[v][0], idx, top); for (usize i = 1 ; i < T[v].size() ; i++) idx = dfs(dfs, T[v][i], idx, T[v][i]); } return idx; }; dfs1(dfs1, root, INVALID, 0u); dfs2(dfs2, root, 0u, root); for (usize i = 0 ; i < m_n ; i++) if (m_dep[m_bottom[m_top[i]]] < m_dep[i]) m_bottom[m_top[i]] = i; } inline usize size() const noexcept { return m_n; } usize size(V v) const noexcept { assert(v < (V)size()); return m_size[v]; } usize depth(V v) const noexcept { assert(v < (V)size()); return m_dep[v]; } V parent(V v) const noexcept { assert(v < (V)size()); return m_par[v]; } V index(V v) const noexcept { assert(v < (V)size()); return m_idx[v]; } V operator[](V v) const noexcept { assert(v < (V)size()); return m_idx[v]; } V top(V v) const noexcept { assert(v < (V)size()); return m_top[v]; } V bottom(V v) const noexcept { assert(v < (V)size()); return m_bottom[m_top[v]]; } std::pair heavyPath(V v) const { assert(v < (V)size()); return {top(v), bottom(v)}; } std::vector> decomp(V s, V t) const { assert(s < (V)size()); assert(t < (V)size()); std::vector> res, ser; while (m_top[s] != m_top[t]) { if (m_dep[m_top[s]] >= m_dep[m_top[t]]) { res.emplace_back(s, m_top[s]); s = m_top[s]; if (m_par[s] != INVALID) s = m_par[s]; } else { ser.emplace_back(m_top[t], t); t = m_top[t]; if (m_par[t] != INVALID) t = m_par[t]; } } res.emplace_back(s, t); std::reverse(ser.begin(), ser.end()); res.insert(res.end(), ser.begin(), ser.end()); return res; } std::vector> operator()(V s, V t) const { return decomp(s, t); } V lca(V u, V v) const { assert(u < (V)size()); assert(v < (V)size()); while (m_top[u] != m_top[v]) { if (m_dep[m_top[u]] >= m_dep[m_top[v]]) { u = m_top[u]; if (m_par[u] != INVALID) u = m_par[u]; } else { v = m_top[v]; if (m_par[v] != INVALID) v = m_par[v]; } } return (m_dep[u] <= m_dep[v] ? u : v); } // pはvの祖先か? bool isAncestor(V v, V p) { assert(v < size()); assert(p < size()); if (m_dep[v] < m_dep[p]) return false; while (v != INVALID and m_top[v] != m_top[p]) { v = m_par[m_top[v]]; } return v != INVALID; } V levelAncestor(V v, usize step) const { assert(v < (V)size()); if (step > m_dep[v]) return INVALID; while (true) { usize dist{m_dep[v] - m_dep[m_top[v]]}; if (dist >= step) break; step -= dist + 1; v = m_par[m_top[v]]; } step = (m_dep[v] - m_dep[m_top[v]]) - step; return m_inv[m_idx[m_top[v]] + step]; } V jump(V s, V t, usize step) const { assert(s < (V)size()); assert(t < (V)size()); V uu{INVALID}, vv{INVALID}; usize d{}; for (auto [u, v] : decomp(s, t)) { usize dist{std::max(m_dep[u], m_dep[v]) - std::min(m_dep[u], m_dep[v])}; if (dist >= step) { uu = u; vv = v; d = dist; break; } step -= dist + 1; } if (uu == INVALID) return INVALID; if (m_dep[uu] <= m_dep[vv]) return m_inv[m_idx[uu] + step]; else return m_inv[m_idx[vv] + (d - step)]; } usize distance(V s, V t) const { assert(s < (V)size()); assert(t < (V)size()); usize res{}; for (auto [u, v] : decomp(s, t)) { if (m_dep[u] > m_dep[v]) std::swap(u, v); res += m_dep[v] - m_dep[u]; } return res; } private: static constexpr V INVALID{static_cast(-1)}; usize m_n{}; std::vector m_par{}, m_top{}, m_idx{}, m_inv{}, m_bottom{}; std::vector m_size{}, m_dep{}; }; } // namespace zawa namespace zawa { namespace concepts { template concept Semigroup = requires { typename T::Element; { T::operation(std::declval(), std::declval()) } -> std::same_as; }; } // namespace concepts } // namespace zawa namespace zawa { namespace concepts { template concept Identitiable = requires { typename T::Element; { T::identity() } -> std::same_as; }; template concept Monoid = Semigroup and Identitiable; } // namespace } // namespace zawa #include #include #include namespace zawa { template class SegmentTree { public: using VM = Monoid; using V = typename VM::Element; using OM = Monoid; using O = typename OM::Element; SegmentTree() = default; explicit SegmentTree(usize n) : m_n{ n }, m_dat(n << 1, VM::identity()) {} explicit SegmentTree(const std::vector& dat) : m_n{ dat.size() }, m_dat(dat.size() << 1, VM::identity()) { for (usize i{} ; i < m_n ; i++) { m_dat[i + m_n] = dat[i]; } for (usize i{m_n} ; i-- ; ) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } [[nodiscard]] inline usize size() const noexcept { return m_n; } [[nodiscard]] V get(usize i) const { assert(i < size()); return m_dat[i + m_n]; } [[nodiscard]] V operator[](usize i) const { assert(i < size()); return m_dat[i + m_n]; } void operation(usize i, const O& value) { assert(i < size()); i += size(); m_dat[i] = OM::operation(m_dat[i], value); while (i = parent(i), i) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } void assign(usize i, const V& value) { assert(i < size()); i += size(); m_dat[i] = value; while (i = parent(i), i) { m_dat[i] = VM::operation(m_dat[left(i)], m_dat[right(i)]); } } [[nodiscard]] V product(u32 l, u32 r) const { assert(l <= r and r <= size()); V L{ VM::identity() }, R{ VM::identity() }; for (l += size(), r += size() ; l < r ; l = parent(l), r = parent(r)) { if (l & 1) { L = VM::operation(L, m_dat[l++]); } if (r & 1) { R = VM::operation(m_dat[--r], R); } } return VM::operation(L, R); } template requires std::predicate [[nodiscard]] usize maxRight(usize l, const F& f) { assert(l < size()); static_assert(std::is_convertible_v>, "maxRight's argument f must be function bool(T)"); assert(f(VM::identity())); usize res{l}, width{1}; V prod{ VM::identity() }; // 現在の見ている頂点の幅をwidthで持つ // 境界がある頂点を含む部分木の根を探す // (折り返す時は必要以上の幅を持つ根になるが、widthを持っているのでオーバーしない) for (l += size() ; res + width <= size() ; l = parent(l), width <<= 1) if (l & 1) { if (not f(VM::operation(prod, m_dat[l]))) break; res += width; prod = VM::operation(prod, m_dat[l++]); } // 根から下って、境界を発見する while (l = left(l), width >>= 1) { if (res + width <= size() and f(VM::operation(prod, m_dat[l]))) { res += width; prod = VM::operation(prod, m_dat[l++]); } } return res; } template requires std::predicate [[nodiscard]] usize minLeft(usize r, const F& f) const { assert(r <= size()); static_assert(std::is_convertible_v>, "minLeft's argument f must be function bool(T)"); assert(f(VM::identity())); usize res{r}, width{1}; V prod{ VM::identity() }; for (r += size() ; res >= width ; r = parent(r), width <<= 1) if (r & 1) { if (not f(VM::operation(m_dat[r - 1], prod))) break; res -= width; prod = VM::operation(prod, m_dat[--r]); } while (r = left(r), width >>= 1) { if (res >= width and f(VM::operation(m_dat[r - 1], prod))) { res -= width; prod = VM::operation(m_dat[--r], prod); } } return res; } friend std::ostream& operator<<(std::ostream& os, const SegmentTree& st) { for (usize i{1} ; i < 2 * st.size() ; i++) { os << st.m_dat[i] << (i + 1 == 2 * st.size() ? "" : " "); } return os; } private: constexpr u32 left(u32 v) const { return v << 1; } constexpr u32 right(u32 v) const { return v << 1 | 1; } constexpr u32 parent(u32 v) const { return v >> 1; } usize m_n; std::vector m_dat; }; } // namespace zawa #include #include #include #include #include namespace ranges = std::ranges; namespace views = std::views; using namespace zawa; #include using namespace std; struct M { using Element = int; static Element identity() { return (int)1e9; } static Element operation(Element L, Element R) { return min(L, R); } }; int N, Q; int main() { #ifdef ONLINE_JUDGE cin.tie(0); cout.tie(0); ios::sync_with_stdio(0); cin >> N; vector> g(N); for (int i = 0 ; i < N - 1 ; i++) { int u, v; cin >> u >> v; u--; v--; g[u].push_back(v); g[v].push_back(u); } HeavyLightDecomposition hld{g}; SegmentTree seg(N), seg2(N); vector>> bk(N); auto upd = [&](int u, int v) -> void { pair cur{hld.depth(v), v}; auto it = bk[u].find(cur); if (it != bk[u].end()) bk[u].erase(it); else bk[u].insert(cur); seg.assign(hld[u], bk[u].size() ? (bk[u].begin()->first - 2 * (int)hld.depth(u)) : M::identity()); seg2.assign(hld[u], bk[u].size() ? bk[u].begin()->first : M::identity()); }; auto leaf_prod = [&](int v) -> int { int u = hld.bottom(v); tie(u, v) = minmax({hld[u], hld[v]}); return seg2.product(u, v + 1); }; cin >> Q; while (Q--) { int T, V; cin >> T >> V; V--; if (T == 1) { for (auto [u, v] : hld(V, 0)) { upd(u, V); if (u != v) upd(v, V); } } else if (T == 2) { int ans = M::identity(); for (auto [u, v] : hld(V, 0)) { if (hld.depth(u) > hld.depth(v)) { ans = min(ans, leaf_prod(u) - 2 * (int)hld.depth(u)); } else { ans = min(ans, leaf_prod(v) - 2 * (int)hld.depth(v)); } tie(u, v) = minmax({hld[u], hld[v]}); ans = min(ans, seg.product(u, v + 1)); } ans += hld.depth(V); cout << ans << '\n'; } else assert(false); } #else cout << "Hello World\n"; #endif }