結果

問題 No.3189 Semifinal Stage
ユーザー zawakasu
提出日時 2025-09-18 00:52:53
言語 C++23
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 661 ms / 4,000 ms
コード長 13,992 bytes
コンパイル時間 2,439 ms
コンパイル使用メモリ 183,520 KB
実行使用メモリ 38,452 KB
最終ジャッジ日時 2025-09-18 00:53:10
合計ジャッジ時間 15,305 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 30
権限があれば一括ダウンロードができます

ソースコード

diff #

// #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 <cstdint>
#include <cstddef>

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 <algorithm>
#include <cassert>
#include <concepts>
#include <cmath>
#include <limits>
#include <utility>
#include <vector>

namespace zawa {

template <std::integral V>
class HeavyLightDecomposition {
public:

    static constexpr V Invalid() noexcept {
        return INVALID;
    }

    HeavyLightDecomposition() = default;

    HeavyLightDecomposition(std::vector<std::vector<V>> 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<V, V> heavyPath(V v) const {
        assert(v < (V)size());
        return {top(v), bottom(v)};
    }

    std::vector<std::pair<V, V>> decomp(V s, V t) const {
        assert(s < (V)size());
        assert(t < (V)size());
        std::vector<std::pair<V, V>> 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<std::pair<V, V>> 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<V>(-1)};

    usize m_n{};

    std::vector<V> m_par{}, m_top{}, m_idx{}, m_inv{}, m_bottom{};

    std::vector<usize> m_size{}, m_dep{};
};

} // namespace zawa




namespace zawa {

namespace concepts {

template <class T>
concept Semigroup = requires {
    typename T::Element;
    { T::operation(std::declval<typename T::Element>(), std::declval<typename T::Element>()) } -> std::same_as<typename T::Element>;
};

} // namespace concepts

} // namespace zawa


namespace zawa {

namespace concepts {

template <class T>
concept Identitiable = requires {
    typename T::Element;
    { T::identity() } -> std::same_as<typename T::Element>;
};

template <class T>
concept Monoid = Semigroup<T> and Identitiable<T>;

} // namespace

} // namespace zawa

#include <functional>
#include <type_traits>
#include <ostream>

namespace zawa {

template <concepts::Monoid Monoid>
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<V>& 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 <class F>
    requires std::predicate<F, V>
    [[nodiscard]] usize maxRight(usize l, const F& f) {
        assert(l < size());
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(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 <class F>
    requires std::predicate<F, V>
    [[nodiscard]] usize minLeft(usize r, const F& f) const {
        assert(r <= size());
        static_assert(std::is_convertible_v<decltype(f), std::function<bool(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<V> m_dat;
};

} // namespace zawa

#include <iostream>
#include <iomanip>
#include <numeric>
#include <tuple>
#include <ranges>
namespace ranges = std::ranges;
namespace views = std::views;
using namespace zawa;
#include <set>
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<vector<int>> 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<M> seg(N), seg2(N);
    vector<set<pair<int, int>>> bk(N);
    auto upd = [&](int u, int v) -> void {
        pair<int, int> 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<int>(ans, seg.product(u, v + 1));
            }
            ans += hld.depth(V);
            cout << ans << '\n';
        }
        else assert(false);
    }
#else
    cout << "Hello World\n";
#endif
}
0