cp-library-cpp

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub suisen-cp/cp-library-cpp

:heavy_check_mark: test/src/tree/heavy_light_decomposition/do_use_segment_tree.test.cpp

Depends on

Code

#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2450"

#include <iostream>
#include <atcoder/lazysegtree>
#include "library/tree/heavy_light_decomposition.hpp"

struct S {
    int len;
    long long pref, max, suff, sum;
    S(int len, long long pref, long long max, long long suff, long long sum) : len(len), pref(pref), max(max), suff(suff), sum(sum) {}
};

constexpr long long INF = std::numeric_limits<int>::max();

S op1(const S s1, const S s2) {
    int len = s1.len + s2.len;
    long long pref = std::max(s1.pref, s1.sum + s2.pref);
    long long max  = std::max({s1.max, s2.max, s1.suff + s2.pref});
    long long suff = std::max(s1.suff + s2.sum, s2.suff);
    long long sum  = s1.sum + s2.sum;
    return {len, pref, max, suff, sum};
}
S op2(const S s1, const S s2) {
    return op1(s2, s1);
}
S e() { 
    return {0, -INF, -INF, -INF, 0};
}
S mapping(long long f, S x) {
    int len = x.len;
    if (f == -INF or len == 0) return x;
    long long max = f >= 0 ? f * len : f;
    return {len, max, max, max, f * len};
}
long long composition(long long f, long long g) {
    return f == -INF ? g : f;
}
long long id() {
    return -INF;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, q;
    std::cin >> n >> q;
    std::vector<long long> w(n);
    for (long long &e : w) {
        std::cin >> e;
    }
    std::vector<std::vector<int>> g(n);
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        std::cin >> u >> v;
        --u, --v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    suisen::HeavyLightDecomposition hld(g);
    atcoder::lazy_segtree<S, op1, e, long long, mapping, composition, id> seg1(n);
    atcoder::lazy_segtree<S, op2, e, long long, mapping, composition, id> seg2(n);
    for (int i = 0; i < n; ++i) {
        hld.update_point(i, [&](int j) {
            seg1.set(j, {1, w[i], w[i], w[i], w[i]});
            seg2.set(j, {1, w[i], w[i], w[i], w[i]});
        });
    }
    for (int i = 0; i < q; ++i) {
        int t, a, b, c;
        std::cin >> t >> a >> b >> c;
        --a, --b;
        if (t == 1) {
            hld.update_path(a, b, [&](int l, int r) {
                seg1.apply(l, r, c);
                seg2.apply(l, r, c);
            });
        } else {
            std::cout << hld.fold_path_noncommutative(
                a, b, e(), op1,
                [&](int l, int r) { return seg1.prod(l, r); },
                [&](int l, int r) { return seg2.prod(l, r); }
            ).max << '\n';
        }
    }
    return 0;
}
#line 1 "test/src/tree/heavy_light_decomposition/do_use_segment_tree.test.cpp"
#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2450"

#include <iostream>
#include <atcoder/lazysegtree>
#line 1 "library/tree/heavy_light_decomposition.hpp"



#line 1 "library/type_traits/type_traits.hpp"



#include <limits>
#line 6 "library/type_traits/type_traits.hpp"
#include <type_traits>

namespace suisen {
    template <typename ...Constraints> using constraints_t = std::enable_if_t<std::conjunction_v<Constraints...>, std::nullptr_t>;

    template <typename T, typename = std::nullptr_t> struct bitnum { static constexpr int value = 0; };
    template <typename T> struct bitnum<T, constraints_t<std::is_integral<T>>> { static constexpr int value = std::numeric_limits<std::make_unsigned_t<T>>::digits; };
    template <typename T> static constexpr int bitnum_v = bitnum<T>::value;
    template <typename T, size_t n> struct is_nbit { static constexpr bool value = bitnum_v<T> == n; };
    template <typename T, size_t n> static constexpr bool is_nbit_v = is_nbit<T, n>::value;

    template <typename T, typename = std::nullptr_t> struct safely_multipliable { using type = T; };
    template <typename T> struct safely_multipliable<T, constraints_t<std::is_signed<T>, is_nbit<T, 32>>> { using type = long long; };
    template <typename T> struct safely_multipliable<T, constraints_t<std::is_signed<T>, is_nbit<T, 64>>> { using type = __int128_t; };
    template <typename T> struct safely_multipliable<T, constraints_t<std::is_unsigned<T>, is_nbit<T, 32>>> { using type = unsigned long long; };
    template <typename T> struct safely_multipliable<T, constraints_t<std::is_unsigned<T>, is_nbit<T, 64>>> { using type = __uint128_t; };
    template <typename T> using safely_multipliable_t = typename safely_multipliable<T>::type;

    template <typename T, typename = void> struct rec_value_type { using type = T; };
    template <typename T> struct rec_value_type<T, std::void_t<typename T::value_type>> {
        using type = typename rec_value_type<typename T::value_type>::type;
    };
    template <typename T> using rec_value_type_t = typename rec_value_type<T>::type;

    template <typename T> class is_iterable {
        template <typename T_> static auto test(T_ e) -> decltype(e.begin(), e.end(), std::true_type{});
        static std::false_type test(...);
    public:
        static constexpr bool value = decltype(test(std::declval<T>()))::value;
    };
    template <typename T> static constexpr bool is_iterable_v = is_iterable<T>::value;
    template <typename T> class is_writable {
        template <typename T_> static auto test(T_ e) -> decltype(std::declval<std::ostream&>() << e, std::true_type{});
        static std::false_type test(...);
    public:
        static constexpr bool value = decltype(test(std::declval<T>()))::value;
    };
    template <typename T> static constexpr bool is_writable_v = is_writable<T>::value;
    template <typename T> class is_readable {
        template <typename T_> static auto test(T_ e) -> decltype(std::declval<std::istream&>() >> e, std::true_type{});
        static std::false_type test(...);
    public:
        static constexpr bool value = decltype(test(std::declval<T>()))::value;
    };
    template <typename T> static constexpr bool is_readable_v = is_readable<T>::value;
} // namespace suisen

#line 5 "library/tree/heavy_light_decomposition.hpp"
#include <vector>

namespace suisen {
class HeavyLightDecomposition {
    public:
        template <typename Q>
        using is_point_update_query = std::is_invocable<Q, int>;
        template <typename Q>
        using is_range_update_query = std::is_invocable<Q, int, int>;
        template <typename Q, typename T>
        using is_point_get_query  = std::is_same<std::invoke_result_t<Q, int>, T>;
        template <typename Q, typename T>
        using is_range_fold_query = std::is_same<std::invoke_result_t<Q, int, int>, T>;

        using Graph = std::vector<std::vector<int>>;

        HeavyLightDecomposition() = default;
        HeavyLightDecomposition(Graph &g) : n(g.size()), visit(n), leave(n), head(n), ord(n), siz(n), par(n, -1), dep(n, 0) {
            for (int i = 0; i < n; ++i) if (par[i] < 0) dfs(g, i, -1);
            int time = 0;
            for (int i = 0; i < n; ++i) if (par[i] < 0) hld(g, i, -1, time);
        }
        HeavyLightDecomposition(Graph &g, const std::vector<int> &roots) : n(g.size()), visit(n), leave(n), head(n), ord(n), siz(n), par(n, -1), dep(n, 0) {
            for (int i : roots) dfs(g, i, -1);
            int time = 0;
            for (int i : roots) hld(g, i, -1, time);
        }
        int size() const {
            return n;
        }
        int lca(int u, int v) const {
            for (;; v = par[head[v]]) {
                if (visit[u] > visit[v]) std::swap(u, v);
                if (head[u] == head[v]) return u;
            }
        }
        int la(int u, int k, int default_value = -1) const {
            if (k < 0) return default_value;
            while (u >= 0) {
                int h = head[u];
                if (visit[u] - k >= visit[h]) return ord[visit[u] - k];
                k -= visit[u] - visit[h] + 1;
                u = par[h];
            }
            return default_value;
        }
        int jump(int u, int v, int d, int default_value = -1) const {
            if (d < 0) return default_value;
            const int w = lca(u, v);
            int uw = dep[u] - dep[w];
            if (d <= uw) return la(u, d);
            int vw = dep[v] - dep[w];
            return d <= uw + vw ? la(v, (uw + vw) - d) : default_value;
        }
        int dist(int u, int v) const {
            return dep[u] + dep[v] - 2 * dep[lca(u, v)];
        }
        template <typename T, typename Q, typename F, constraints_t<is_range_fold_query<Q, T>, std::is_invocable_r<T, F, T, T>> = nullptr>
        T fold_path(int u, int v, T identity, F bin_op, Q fold_query, bool is_edge_query = false) const {
            T res = identity;
            for (;; v = par[head[v]]) {
                if (visit[u] > visit[v]) std::swap(u, v);
                if (head[u] == head[v]) break;
                res = bin_op(fold_query(visit[head[v]], visit[v] + 1), res);
            }
            return bin_op(fold_query(visit[u] + is_edge_query, visit[v] + 1), res);
        }
        template <
            typename T, typename Q1, typename Q2, typename F,
            constraints_t<is_range_fold_query<Q1, T>, is_range_fold_query<Q2, T>, std::is_invocable_r<T, F, T, T>> = nullptr
        >
        T fold_path_noncommutative(int u, int v, T identity, F bin_op, Q1 fold_query, Q2 fold_query_rev, bool is_edge_query = false) const {
            T res_u = identity, res_v = identity;
            // a := lca(u, v)
            // res = fold(u -> a) + fold(a -> v)
            while (head[u] != head[v]) {
                if (visit[u] < visit[v]) { // a -> v
                    res_v = bin_op(fold_query(visit[head[v]], visit[v] + 1), res_v);
                    v = par[head[v]];
                } else { // u -> a
                    res_u = bin_op(res_u, fold_query_rev(visit[head[u]], visit[u] + 1));
                    u = par[head[u]];
                }
            }
            if (visit[u] < visit[v]) { // a = u
                res_v = bin_op(fold_query(visit[u] + is_edge_query, visit[v] + 1), res_v);
            } else { // a = v
                res_u = bin_op(res_u, fold_query_rev(visit[v] + is_edge_query, visit[u] + 1));
            }
            return bin_op(res_u, res_v);
        }
        template <typename Q, constraints_t<is_range_update_query<Q>> = nullptr>
        void update_path(int u, int v, Q update_query, bool is_edge_query = false) const {
            for (;; v = par[head[v]]) {
                if (visit[u] > visit[v]) std::swap(u, v);
                if (head[u] == head[v]) break;
                update_query(visit[head[v]], visit[v] + 1);
            }
            update_query(visit[u] + is_edge_query, visit[v] + 1);
        }
        template <typename T, typename Q, constraints_t<is_range_fold_query<Q, T>> = nullptr>
        T fold_subtree(int u, Q fold_query, bool is_edge_query = false) const {
            return fold_query(visit[u] + is_edge_query, leave[u]);
        }
        template <typename Q, constraints_t<is_range_update_query<Q>> = nullptr>
        void update_subtree(int u, Q update_query, bool is_edge_query = false) const {
            update_query(visit[u] + is_edge_query, leave[u]);
        }
        template <typename T, typename Q, constraints_t<is_point_get_query<Q, T>> = nullptr>
        T get_point(int u, Q get_query) const {
            return get_query(visit[u]);
        }
        template <typename Q, constraints_t<is_point_update_query<Q>> = nullptr>
        void update_point(int u, Q update_query) const {
            update_query(visit[u]);
        }
        std::vector<int> inv_ids() const {
            std::vector<int> inv(n);
            for (int i = 0; i < n; ++i) inv[visit[i]] = i;
            return inv;
        }
        int get_visit_time(int u) const {
            return visit[u];
        }
        int get_leave_time(int u) const {
            return leave[u];
        }
        int get_head(int u) const {
            return head[u];
        }
        int get_kth_visited(int k) const {
            return ord[k];
        }
        int get_subtree_size(int u) const {
            return siz[u];
        }
        int get_parent(int u) const {
            return par[u];
        }
        int get_depth(int u) const {
            return dep[u];
        }
        std::vector<int> get_roots() const {
            std::vector<int> res;
            for (int i = 0; i < n; ++i) if (par[i] < 0) res.push_back(i);
            return res;
        }
    private:
        int n;
        std::vector<int> visit, leave, head, ord, siz, par, dep;
        int dfs(Graph &g, int u, int p) {
            par[u] = p;
            siz[u] = 1;
            int max_size = 0;
            for (int &v : g[u]) {
                if (v == p) continue;
                dep[v] = dep[u] + 1;
                siz[u] += dfs(g, v, u);
                if (max_size < siz[v]) {
                    max_size = siz[v];
                    std::swap(g[u].front(), v);
                }
            }
            return siz[u];
        }
        void hld(Graph &g, int u, int p, int &time) {
            visit[u] = time, ord[time] = u, ++time;
            head[u] = p >= 0 and g[p].front() == u ? head[p] : u;
            for (int v : g[u]) {
                if (v != p) hld(g, v, u, time);
            }
            leave[u] = time;
        }
};
} // namespace suisen


#line 6 "test/src/tree/heavy_light_decomposition/do_use_segment_tree.test.cpp"

struct S {
    int len;
    long long pref, max, suff, sum;
    S(int len, long long pref, long long max, long long suff, long long sum) : len(len), pref(pref), max(max), suff(suff), sum(sum) {}
};

constexpr long long INF = std::numeric_limits<int>::max();

S op1(const S s1, const S s2) {
    int len = s1.len + s2.len;
    long long pref = std::max(s1.pref, s1.sum + s2.pref);
    long long max  = std::max({s1.max, s2.max, s1.suff + s2.pref});
    long long suff = std::max(s1.suff + s2.sum, s2.suff);
    long long sum  = s1.sum + s2.sum;
    return {len, pref, max, suff, sum};
}
S op2(const S s1, const S s2) {
    return op1(s2, s1);
}
S e() { 
    return {0, -INF, -INF, -INF, 0};
}
S mapping(long long f, S x) {
    int len = x.len;
    if (f == -INF or len == 0) return x;
    long long max = f >= 0 ? f * len : f;
    return {len, max, max, max, f * len};
}
long long composition(long long f, long long g) {
    return f == -INF ? g : f;
}
long long id() {
    return -INF;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, q;
    std::cin >> n >> q;
    std::vector<long long> w(n);
    for (long long &e : w) {
        std::cin >> e;
    }
    std::vector<std::vector<int>> g(n);
    for (int i = 0; i < n - 1; ++i) {
        int u, v;
        std::cin >> u >> v;
        --u, --v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    suisen::HeavyLightDecomposition hld(g);
    atcoder::lazy_segtree<S, op1, e, long long, mapping, composition, id> seg1(n);
    atcoder::lazy_segtree<S, op2, e, long long, mapping, composition, id> seg2(n);
    for (int i = 0; i < n; ++i) {
        hld.update_point(i, [&](int j) {
            seg1.set(j, {1, w[i], w[i], w[i], w[i]});
            seg2.set(j, {1, w[i], w[i], w[i], w[i]});
        });
    }
    for (int i = 0; i < q; ++i) {
        int t, a, b, c;
        std::cin >> t >> a >> b >> c;
        --a, --b;
        if (t == 1) {
            hld.update_path(a, b, [&](int l, int r) {
                seg1.apply(l, r, c);
                seg2.apply(l, r, c);
            });
        } else {
            std::cout << hld.fold_path_noncommutative(
                a, b, e(), op1,
                [&](int l, int r) { return seg1.prod(l, r); },
                [&](int l, int r) { return seg2.prod(l, r); }
            ).max << '\n';
        }
    }
    return 0;
}
Back to top page