Skip to the content.

:heavy_check_mark: library/datastructure/Doubling.hpp

Depends on

Verified with

Code

template <typename Monoid, int LOG> class Doubling {
    using X = typename Monoid::value_type;
    int n;
    bool is_prepared;

    using P = std::pair<int, X>;
    static constexpr P unit = {-1, Monoid::unit()};
    std::vector<std::vector<P>> DP;

    // a から 2^k 動く
    P k_move(const P &a, int k) {
        if (a.first == -1)
            return a;
        const auto [now, val] = a;
        const auto [nxt, cost] = DP[k][now];
        return {nxt, Monoid::op(val, cost)};
    }

    void build() {
        is_prepared = true;
        for (int k = 0; k < LOG - 1; k++)
            for (int v = 0; v < n; v++)
                DP[k + 1][v] = k_move(DP[k][v], k);
    }

  public:
    Doubling() = default;
    Doubling(int n) : n(n), is_prepared(false) {
        DP.assign(LOG, std::vector<P>(n, unit));
    }

    void add_arc(int from, int to, X x) {
        assert(!is_prepared);
        assert(-1 <= to and to < n);
        DP[0][from] = {to, x};
    }

    // [終点,値] 辺が出てない場所から移動する場合は -1 に着く
    P calc(int s, long long step) {
        assert(step <= (1LL << LOG));
        if (!is_prepared)
            build();

        P res{s, Monoid::unit()};
        for (int k = 0; step; k++, step >>= 1)
            if (step & 1)
                res = k_move(res, k);
        return res;
    }
};
#line 1 "library/datastructure/Doubling.hpp"
template <typename Monoid, int LOG> class Doubling {
    using X = typename Monoid::value_type;
    int n;
    bool is_prepared;

    using P = std::pair<int, X>;
    static constexpr P unit = {-1, Monoid::unit()};
    std::vector<std::vector<P>> DP;

    // a から 2^k 動く
    P k_move(const P &a, int k) {
        if (a.first == -1)
            return a;
        const auto [now, val] = a;
        const auto [nxt, cost] = DP[k][now];
        return {nxt, Monoid::op(val, cost)};
    }

    void build() {
        is_prepared = true;
        for (int k = 0; k < LOG - 1; k++)
            for (int v = 0; v < n; v++)
                DP[k + 1][v] = k_move(DP[k][v], k);
    }

  public:
    Doubling() = default;
    Doubling(int n) : n(n), is_prepared(false) {
        DP.assign(LOG, std::vector<P>(n, unit));
    }

    void add_arc(int from, int to, X x) {
        assert(!is_prepared);
        assert(-1 <= to and to < n);
        DP[0][from] = {to, x};
    }

    // [終点,値] 辺が出てない場所から移動する場合は -1 に着く
    P calc(int s, long long step) {
        assert(step <= (1LL << LOG));
        if (!is_prepared)
            build();

        P res{s, Monoid::unit()};
        for (int k = 0; step; k++, step >>= 1)
            if (step & 1)
                res = k_move(res, k);
        return res;
    }
};
Back to top page