結果

問題 No.1326 ふたりのDominator
ユーザー FeleriusFelerius
提出日時 2022-02-13 01:34:34
言語 C++17
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 87 ms / 2,000 ms
コード長 14,622 bytes
コンパイル時間 4,743 ms
コンパイル使用メモリ 339,644 KB
実行使用メモリ 29,740 KB
最終ジャッジ日時 2023-10-24 10:43:01
合計ジャッジ時間 6,962 ms
ジャッジサーバーID
(参考情報)
judge13 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,348 KB
testcase_01 AC 2 ms
4,348 KB
testcase_02 AC 2 ms
4,348 KB
testcase_03 AC 2 ms
4,348 KB
testcase_04 AC 2 ms
4,348 KB
testcase_05 AC 2 ms
4,348 KB
testcase_06 AC 2 ms
4,348 KB
testcase_07 AC 2 ms
4,348 KB
testcase_08 AC 3 ms
4,348 KB
testcase_09 AC 2 ms
4,348 KB
testcase_10 AC 3 ms
4,348 KB
testcase_11 AC 3 ms
4,348 KB
testcase_12 AC 71 ms
21,052 KB
testcase_13 AC 64 ms
21,056 KB
testcase_14 AC 67 ms
21,068 KB
testcase_15 AC 68 ms
20,836 KB
testcase_16 AC 60 ms
20,892 KB
testcase_17 AC 60 ms
20,248 KB
testcase_18 AC 62 ms
20,412 KB
testcase_19 AC 54 ms
22,924 KB
testcase_20 AC 68 ms
27,252 KB
testcase_21 AC 77 ms
27,320 KB
testcase_22 AC 87 ms
29,740 KB
testcase_23 AC 53 ms
21,336 KB
testcase_24 AC 62 ms
21,056 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#pragma GCC optimize("fast-math")

#include <bits/stdc++.h>
#ifdef LOCAL
#  include <dbg.h>
#else
#  define dbg(...) do {} while (0)
#endif

#define cp_lib_4th(_1, _2, _3, x, ...)  x
#define cp_lib_rep(i, l, r)             for (int i = (l); (i) < (r); ++(i))
#define cp_lib_rep0(i, r)               cp_lib_rep(i, 0, r)
#define rep(...)                        cp_lib_4th(__VA_ARGS__, cp_lib_rep, cp_lib_rep0, _)(__VA_ARGS__)
#define cp_lib_repr(i, r, l, ...)       for (int i = (r); (i) >= (l); --(i))
#define repr(...)                       cp_lib_repr(__VA_ARGS__, 0)
#define all(a)                          ::begin(a),::end(a)
#define trav(a, b)                      for (auto&& a : (b))

using namespace std;
using ll = long long;
using ld = long double;
[[maybe_unused]] static constexpr int INF = int(1e9 + 5);
[[maybe_unused]] static constexpr ll INFL = ll(INF) * INF;
template <class C> int sz(const C& c) { return int(::size(c)); }


#ifdef CP_LIB_DEBUG
#define cp_lib_assert(expr) \
    do { if (!(expr)) { \
        ::cerr << "assertion failed: " << #expr << " (" << __FILE__ << ':' << __LINE__ << ")\n"; \
        ::abort(); \
    } } while (0)
#else
#define cp_lib_assert(expr)
#endif


#if __cplusplus < 202002L
struct identity { template <class T> constexpr T&& operator()(T&& t) const noexcept { return forward<T>(t); }; };
#endif
#if __cpp_lib_remove_cvref < 201711L
template <class T> using remove_cvref_t = remove_cv_t<remove_reference_t<T>>;
#endif

namespace cp_lib_type_meta {
    struct NoOp { template <class... Args> constexpr void operator()(Args&&...) const noexcept {} };
    template <class T, class = void> constexpr bool is_tuple_like = false;
    template <class T> constexpr bool is_tuple_like<T, void_t<tuple_element_t<0, T>>> = true;
}


namespace cp_lib_modint { struct ModIntTag {}; }
#include <unistd.h>

namespace cp_lib_io {
    constexpr int BUF_SIZE = 1 << 20;
    constexpr array<array<char, 4>, 10'000> DIGITS = []{
        array<array<char, 4>, 10'000> digits{};
        for (int i = 3, d = 1; i >= 0; --i, d *= 10)
            rep(j, 10'000)
                digits[j][i] = char('0' + j / d % 10);
        return digits;
    }();
    array<char, BUF_SIZE> ibuf, obuf;
    char *iptr = data(ibuf), *iend = iptr, *optr = data(obuf);

    template <class T> constexpr bool is_std_array = false;
    template <class T, size_t I> constexpr bool is_std_array<array<T, I>> = true;

    void flush() {
        for (auto* p = begin(obuf); p != optr; p += write(STDOUT_FILENO, p, optr - p));
        optr = begin(obuf);
    }
    int _flush_atexit = []{ atexit(flush); return 0; }();

    void refill() {
        memmove(begin(ibuf), iptr, iend - iptr);
        iend -= iptr - begin(ibuf);
        iptr = begin(ibuf);
        iend += read(STDIN_FILENO, iend, end(ibuf) - 1 - iend);
        *iend = '\0';
    }

    template <class T, class T2 = remove_cvref_t<T>>
    void print(T&& val) {
        if (end(obuf) - optr < 64)
            flush();

        if constexpr (is_same_v<T2, char>)
            *optr++ = val;
        else if constexpr (is_same_v<T2, bool> || is_same_v<T2, vector<bool>::reference>)
            return print(int(val));
        else if constexpr (is_integral_v<T2> && is_signed_v<T2>) {
            if (val < 0)
                *optr++ = '-';
            using U = make_unsigned_t<T2>;
            return print(U(val < 0 ? -U(val) : U(val)));
        } else if constexpr (is_integral_v<T2> && is_unsigned_v<T2>) {
            T2 val2 = val;
            array<char, 64> tmp;
            char* tptr = end(tmp);
            while (val2 >= 10'000)
                tptr -= 4, memcpy(tptr, &DIGITS[val2 % 10'000][0], 4), val2 /= T2(10'000);
            int d = (val2 >= 100 ? (val2 >= 1000 ? 4 : 3) : (val2 >= 10 ? 2 : 1));
            memcpy(optr, &DIGITS[val2][4 - d], d);
            memcpy(optr + d, tptr, end(tmp) - tptr);
            optr += d + int(end(tmp) - tptr);
        } else if constexpr (is_floating_point_v<T2>)
            optr += sprintf(optr, "%.30Lf", (long double)val);
        else if constexpr (is_convertible_v<T, string_view>) {
            string_view sv(val);
            if (sz(sv) + 1 <= end(obuf) - optr)
                memcpy(optr, data(sv), sz(sv)), optr += sz(sv);
            else {
                flush();
                for (auto *p = data(sv), *pe = p + sz(sv); p != pe; p += write(STDOUT_FILENO, p, pe - p));
            }
        } else if constexpr (is_base_of_v<cp_lib_modint::ModIntTag, T2>)
            return print(decltype(T2::mod())(val));
        else if constexpr (cp_lib_type_meta::is_tuple_like<T2> && !is_std_array<T2>)
            return apply([](auto&&... items) { (print(items), ...); }, forward<T>(val));
        else {
            trav(item, val)
                print(item);
            return;
        }
        *optr++ = ' ';
    }

    template <class T>
    void read(T& val) {
        auto skip_ws = [] {
            do {
                for (; iptr != iend && *iptr <= ' '; ++iptr);
                if (iend - iptr < 64)
                    refill();
            } while (*iptr <= ' ');
        };
        auto read_other = [&](auto other) {
            read(other);
            return other;
        };

        if constexpr (is_same_v<T, char>)
            skip_ws(), val = *iptr++;
        else if constexpr (is_same_v<T, bool> || is_same_v<T, vector<bool>::reference>) {
            val = bool(read_other(uint8_t()));
        } else if constexpr (is_base_of_v<cp_lib_modint::ModIntTag, T>) {
            val = T(read_other(ll()));
        } else if constexpr (is_integral_v<T>) {
            skip_ws();
            if (is_signed_v<T> && *iptr == '-')
                ++iptr, val = T(-read_other(make_unsigned_t<T>()));
            else
                for (val = 0; iptr != iend && *iptr > ' '; val = T(10 * val + (*iptr++ & 15)));
        } else if constexpr (is_floating_point_v<T>)
            skip_ws(), val = T(strtold(iptr, &iptr));
        else if constexpr (is_same_v<T, string>) {
            skip_ws();
            val.clear();
            do {
                auto* after = find_if(iptr, iend, [](char c) { return c <= ' '; });
                val.append(iptr, after);
                if ((iptr = after) != iend)
                    break;
                refill();
            } while (iptr != iend);
        } else if constexpr (cp_lib_type_meta::is_tuple_like<T> && !is_std_array<T>)
            apply([](auto&... items) { (read(items), ...); }, val);
        else
            trav(item, val)
                read(item);
    }
}

using cp_lib_io::flush;

template <class... Args>
void print(Args&&... args) { (cp_lib_io::print(forward<Args>(args)), ...); }

template <class... Args>
void println(Args&&... args) {
    if (sizeof...(Args))
        (cp_lib_io::print(forward<Args>(args)), ...), *(cp_lib_io::optr - 1) = '\n';
    else
        print('\n'), --cp_lib_io::optr;
}

template <class... Args>
void read(Args&... args) { (cp_lib_io::read(args), ...); }



template <class T> constexpr inline bool is_pow2(T n) { return n && !(n & (n - 1)); }
template <class T> constexpr inline int floor_log2(T n) { return n ? 63 - __builtin_clzll(n) : 0; }
template <class T> constexpr inline int ceil_log2(T n) { return n ? floor_log2(n) + !is_pow2(n) : 0; }

namespace cp_lib_rmq {
    template <class T, bool Max> T minmax(T a, T b) { return (a < b) ^ Max ? a : b; }
}

template <class T, T (*Combine)(T, T)>
struct SparseTable {
    vector<vector<T>> d = {};

    SparseTable() = default;
    explicit SparseTable(const vector<T>& v) {
        int n = sz(v), k = floor_log2(n);
        d.assign(k + 1, v);
        rep(i, k) rep(j, n)
            d[i + 1][j] = Combine(d[i][j], d[i][min(j + (1 << i), n - 1)]);
    }

    // Aggregate for [l, r)
    T query(int l, int r) const {
        int k = floor_log2(r - l);
        return Combine(d[k][l], d[k][r - (1 << k)]);
    }
};

template <class T>
using Rmq = SparseTable<T, cp_lib_rmq::minmax<T, false>>;
template <class T>
using Rmaxq = SparseTable<T, cp_lib_rmq::minmax<T, true>>;


template <class A, class M>
struct Graph {
    const A& adj;
    int n;
    M map;

    Graph(const A& adj_, int n_, M map_) : adj(adj_), n(n_), map(move(map_)) {}
    Graph(const A& adj_, M map_) : Graph(adj_, sz(adj_), move(map_)) {}
    Graph(const A& adj_, int n_) : Graph(adj_, n_, identity()) {}
    explicit Graph(const A& adj_) : Graph(adj_, identity()) {}
};

template <class A> Graph(const A&, int) -> Graph<A, identity>;
template <class A> Graph(const A&) -> Graph<A, identity>;

struct LowestCommonAncestor {
    vector<int> time, euler;
    Rmq<int> rmq;

    template <class G, class = enable_if_t<!is_same_v<LowestCommonAncestor, remove_cvref_t<G>>>>
    LowestCommonAncestor(G&& graph, int root = 0) {
        auto [adj, n, to] = Graph(forward<G>(graph));
        if (!n) return;
        time = vector(n, -1);
        vector<int> d;
        auto dfs = [&, t=1, &adj=adj, &to=to](int v, int p, int tp, auto&& self) mutable -> void {
            euler.push_back(p);
            d.push_back(tp);
            time[v] = t++;
            trav(e, adj[v])
                if (to(e) != p)
                    self(to(e), v, time[v], self);
        };
        dfs(root, -1, 0, dfs);
        rep(i, n)
            if (time[i] == -1)
                dfs(i, -1, 0, dfs);
        rmq = Rmq<int>(d);
    }

    int lca(int u, int v) const {
        if (u == v) return u;
        auto [l, r] = minmax(time[u], time[v]);
        return euler[rmq.query(l, r)];
    }

    bool on_path(int v, pair<int, int> path) const {
        auto [a, b] = path;
        auto av = lca(a, v), bv = lca(b, v), ab = lca(a, b);
        return av != -1 && bv != -1 && ab != -1 && minmax(av, bv) == minmax(v, ab);
    }

    bool is_ancestor(int u, int v) const { return lca(u, v) == u; }
};

template <class A, class M>
struct NewGraph {
    A& adj;
    int n;
    M map;

    using Mapped = decltype(declval<M>()(*begin(declval<A>()[0])));

    NewGraph(A& adj_, M map_) : adj(adj_), n(sz(adj)), map(move(map_)) {}
    explicit NewGraph(A& adj_) : NewGraph(adj_, identity()) {}
};

template <class A> NewGraph(A&) -> NewGraph<A, identity>;

template <class G, class OnComp>
void biconnected_components(G&& graph, OnComp&& on_comp) {
    auto [adj, n, map] = NewGraph(forward<G>(graph));
    auto normalize = [&](auto mapped) {
        if constexpr(is_convertible_v<int, decltype(mapped)>)
            return pair(int(mapped), 0);
        else
            return mapped;
    };
    vector idx(n, INF);
    vector<pair<int, decltype(begin(adj[0]))>> stack;

    auto dfs = [&, &adj = adj, &map = map](int v, pair<int, int> pe, auto&& self) -> int {
        int up = idx[v] = sz(stack), cnt = 0;
        for (auto it = begin(adj[v]); it != end(adj[v]); ++it) {
            auto [v2, e] = normalize(map(*it));
            if (pair(v2, e) == pe)
                continue;
            up = min(up, idx[v2]);
            if (idx[v2] == INF || idx[v2] < idx[v])
                stack.emplace_back(v, it);
            if (idx[v2] != INF)
                continue;

            int up2 = self(v2, pair(v, e), self);
            up = min(up, up2);
            if (up2 >= idx[v]) {
                auto cut_v = (pe.first == -1 && !cnt++ ? nullopt : optional(v));
                on_comp(cut_v, begin(stack) + idx[v2] - 1, end(stack));
                stack.resize(idx[v2] - 1);
            }
        }
        return up;
    };

    rep(i, n)
        if (idx[i] == INF)
            dfs(i, pair(-1, 0), dfs);
}

template <class G>
vector<vector<int>> block_vertex_tree(G&& graph) {
    NewGraph g(forward<G>(graph));
    vector adj(g.n, vector<int>());
    biconnected_components(g, [&](auto, auto it, auto it_end) {
        int vc = sz(adj);
        adj.emplace_back();
        for (; it != it_end; ++it)
            for (int v : {it->first, g.map(*it->second)})
                if (!sz(adj[v]) || adj[v].back() != vc)
                    adj[v].push_back(vc), adj[vc].push_back(v);
    });
    return adj;
}

int main() {
    // int n, m; read(n, m);
    // vector adj(n, vector<pair<int, int>>());
    // rep(i, m) {
    //     int u, v; read(u, v);
    //     adj[u].emplace_back(v, i);
    //     adj[v].emplace_back(u, i);
    // }

    // vector<vector<int>> bicomps;
    // biconnected_components(adj, [&](auto, auto it, auto it_end) {
    //     auto& comp = bicomps.emplace_back();
    //     for (; it != it_end; ++it)
    //         comp.push_back(it->second->second);
    // });

    // println(sz(bicomps));
    // trav(comp, bicomps)
    //     println(sz(comp), comp);


    // int n, m; read(n, m);
    // vector adj(n, vector<int>());
    // rep(_, m) {
    //     int u, v; read(u, v);
    //     adj[u].push_back(v);
    //     adj[v].push_back(u);
    // }

    // set<int> cut_vertices;
    // biconnected_components(adj, [&](auto cut_v, auto, auto) {
    //     if (cut_v)
    //         cut_vertices.emplace(*cut_v);
    // });

    // trav(v, cut_vertices)
    //     println(v);


    // int n, m; read(n, m);
    // vector w(n, 0);
    // read(w);
    // vector adj(n, vector<int>());
    // rep(_, m) {
    //     int u, v; read(u, v); --u, --v;
    //     adj[u].push_back(v);
    //     adj[v].push_back(u);
    // }

    // auto bvt = block_vertex_tree(adj);
    // int nt = sz(bvt);
    // vector wsum(nt, 0ll);
    // copy(all(w), begin(wsum));
    // auto dfs = [&](int v, int p, auto&& self) -> void {
    //     trav(v2, bvt[v])
    //         if (v2 != p)
    //             self(v2, v, self), wsum[v] += wsum[v2];
    // };
    // dfs(0, -1, dfs);

    // rep(i, n) {
    //     if (sz(bvt[i]) == 1) {
    //         println(wsum[0] - w[i]);
    //         continue;
    //     }

    //     ll mx = wsum[0] - wsum[i];
    //     trav(v, bvt[i])
    //         if (wsum[v] < wsum[i])
    //             mx = max(mx, wsum[v]);
    //     println(mx);
    // }


    int n, m; read(n, m);
    vector adj(n, vector<int>());
    rep(_, m) {
        int u, v; read(u, v); --u, --v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }

    auto bvt = block_vertex_tree(adj);
    int nt = sz(bvt);
    LowestCommonAncestor lca(bvt);
    vector depth(nt, 0);
    auto dfs = [&](int v, int p, auto&& self) -> void {
        trav(v2, bvt[v])
            if (v2 != p)
                depth[v2] = depth[v] + 1, self(v2, v, self);
    };
    dfs(0, -1, dfs);

    int q; read(q);
    while (q--) {
        int u, v; read(u, v); --u, --v;
        int d = depth[u] + depth[v] - 2 * depth[lca.lca(u, v)];
        println(u == v ? 0 : (d - 2) / 2);
    }
}
0