competitive-programming-library

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

View the Project on GitHub kmyk/competitive-programming-library

:heavy_check_mark: data_structure/li_chao_tree.segment_add_get_min.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/segment_add_get_min"
#include "../data_structure/li_chao_tree.hpp"
#include "../utils/macros.hpp"
#include <cstdio>
#include <climits>
#include <tuple>
#include <vector>
using namespace std;

int main() {
    // input
    int n, q; scanf("%d%d", &n, &q);
    vector<int64_t> xs;
    vector<tuple<int64_t, int64_t, int64_t, int64_t> > segments;
    REP (i, n) {
        int64_t l, r, a, b; scanf("%lld%lld%lld%lld", &l, &r, &a, &b);
        xs.push_back(l);
        xs.push_back(r);
        segments.emplace_back(l, r, a, b);
    }
    vector<tuple<int, int64_t, int64_t, int64_t, int64_t, int64_t> > queries;
    REP (j, q) {
        int t; scanf("%d", &t);
        if (t == 0) {
            int64_t l, r, a, b; scanf("%lld%lld%lld%lld", &l, &r, &a, &b);
            xs.push_back(l);
            xs.push_back(r);
            queries.emplace_back(t, l, r, a, b, -1);
        } else if (t == 1) {
            int64_t p; scanf("%lld", &p);
            xs.push_back(p);
            queries.emplace_back(t, -1, -1, -1, -1, p);
        } else {
            assert (false);
        }
    }

    // construct
    sort(ALL(xs));
    xs.erase(unique(ALL(xs)), xs.end());
    li_chao_tree lichao(xs);

    // output
    for (auto [l, r, a, b] : segments) {
        lichao.add_segment(l, r, a, b);
    }
    for (auto [t, l, r, a, b, p] : queries) {
        if (t == 0) {
            lichao.add_segment(l, r, a, b);
        } else if (t == 1) {
            int64_t q = lichao.get_min(p);
            if (q == INT64_MAX) {
                printf("INFINITY\n");
            } else {
                printf("%lld\n", q);
            }
        } else {
            assert (false);
        }
    }
    return 0;
}
#line 1 "data_structure/li_chao_tree.segment_add_get_min.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/segment_add_get_min"
#line 2 "data_structure/li_chao_tree.hpp"
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <utility>
#include <vector>
#line 2 "utils/macros.hpp"
#define REP(i, n) for (int i = 0; (i) < (int)(n); ++ (i))
#define REP3(i, m, n) for (int i = (m); (i) < (int)(n); ++ (i))
#define REP_R(i, n) for (int i = (int)(n) - 1; (i) >= 0; -- (i))
#define REP3R(i, m, n) for (int i = (int)(n) - 1; (i) >= (int)(m); -- (i))
#define ALL(x) std::begin(x), std::end(x)
#line 8 "data_structure/li_chao_tree.hpp"

/**
 * @brief Li-Chao tree
 * @docs data_structure/li_chao_tree.md
 */
struct li_chao_tree {
    int k;
    std::vector<std::pair<int64_t, int64_t> > f;
    std::vector<int64_t> x;
    std::vector<int64_t> y;
    li_chao_tree() = default;
    li_chao_tree(const std::vector<int64_t> & x_) : x(x_) {
        assert (std::is_sorted(ALL(x)));
        k = 0; while ((1 << k) < x.size()) ++ k;
        f.resize((1 << k) - 1, std::make_pair(0, std::numeric_limits<int64_t>::max()));
        y.resize(x.size(), std::numeric_limits<int64_t>::max());
    }
    /**
     * @note i is a point on the original space
     */
    int64_t get_min(int64_t i) {
        i = std::lower_bound(ALL(x), i) - x.begin();
        return get_min_compressed(i);
    }
    int64_t get_min_compressed(int i) {  // 0-based
        assert (0 <= i and i < x.size());
        int64_t z = y[i];
        for (int j = (i + (1 << k)) / 2; j > 0; j /= 2) {  // 1-based
            z = std::min(z, f[j - 1].first * x[i] + f[j - 1].second);
        }
        return z;
    }
    /**
     * @note [l, r) is an interval on the original space
     */
    void add_segment(int64_t l, int64_t r, int64_t a, int64_t b) {
        l = std::lower_bound(ALL(x), l) - x.begin();
        r = std::lower_bound(ALL(x), r) - x.begin();
        add_segment_compressed(l, r, a, b);
    }
    void add_segment_compressed(int64_t l, int64_t r, int64_t a, int64_t b) {
        assert (0 <= l and l <= r and r <= x.size());
        add_segment_compressed(0, 0, 1 << k, l, r, a, b);
    }
    void add_segment_compressed(int i, int il, int ir, int l, int r, int64_t a, int64_t b) {
        if (l <= il and ir <= r) {  // 0-based
            if (i >= (1 << k) - 1) {
                int j = i - (1 << k) + 1;
                y[j] = std::min(y[j], a * x[j] + b);
            } else {
                int64_t xl = x[il];
                int64_t xr = x[ir - 1];  // [xl, xr]
                int64_t yl1 = f[i].first * xl + f[i].second;
                int64_t yr1 = f[i].first * xr + f[i].second;
                int64_t yl2 = a * xl + b;
                int64_t yr2 = a * xr + b;
                if (yl1 <= yl2 and yr1 <= yr2) {
                    // if forall x in [l, r]. f(x) <= g(x), then do nothing
                    // nop
                } else if (yl2 <= yl1 and yr2 <= yr1) {
                    // if forall x in [l, r]. g(x) <= f(x), then replace f with g
                    f[i] = std::make_pair(a, b);
                } else {
                    int64_t xm = x[(il + ir) / 2];
                    int64_t ym1 = f[i].first * xm + f[i].second;
                    int64_t ym2 = a * xm + b;
                    if (yl1 <= yl2 and ym1 <= ym2) {
                        // if forall x in [l, m]. f(x) <= g(x), then do recursion for [m, r] with f
                        add_segment_compressed(2 * i + 2, (il + ir) / 2, ir, l, r, a, b);
                    } else if (yl2 <= yl1 and ym2 <= ym1) {
                        // if forall x in [l, m]. g(x) <= f(x), then replace f with g and do recursion for [m, r] with g
                        std::swap(a, f[i].first);
                        std::swap(b, f[i].second);
                        add_segment_compressed(2 * i + 2, (il + ir) / 2, ir, l, r, a, b);
                    } else if (ym1 <= ym2 and yr1 <= yr2) {
                        // if forall x in [m, r]. f(x) <= g(x), then do recursion for [l, m] with f
                        add_segment_compressed(2 * i + 1, il, (il + ir) / 2, l, r, a, b);
                    } else if (ym2 <= ym1 and yr2 <= yr1) {
                        // if forall x in [m, r]. g(x) <= f(x), then replace f with g and do recursion for [l, m] with g
                        std::swap(a, f[i].first);
                        std::swap(b, f[i].second);
                        add_segment_compressed(2 * i + 1, il, (il + ir) / 2, l, r, a, b);
                    } else {
                        assert (false);
                    }
                }
            }
        } else if (ir <= l or r <= il) {
            // nop
        } else {
            add_segment_compressed(2 * i + 1, il, (il + ir) / 2, l, r, a, b);
            add_segment_compressed(2 * i + 2, (il + ir) / 2, ir, l, r, a, b);
        }
    }
};
#line 4 "data_structure/li_chao_tree.segment_add_get_min.test.cpp"
#include <cstdio>
#include <climits>
#include <tuple>
#line 8 "data_structure/li_chao_tree.segment_add_get_min.test.cpp"
using namespace std;

int main() {
    // input
    int n, q; scanf("%d%d", &n, &q);
    vector<int64_t> xs;
    vector<tuple<int64_t, int64_t, int64_t, int64_t> > segments;
    REP (i, n) {
        int64_t l, r, a, b; scanf("%lld%lld%lld%lld", &l, &r, &a, &b);
        xs.push_back(l);
        xs.push_back(r);
        segments.emplace_back(l, r, a, b);
    }
    vector<tuple<int, int64_t, int64_t, int64_t, int64_t, int64_t> > queries;
    REP (j, q) {
        int t; scanf("%d", &t);
        if (t == 0) {
            int64_t l, r, a, b; scanf("%lld%lld%lld%lld", &l, &r, &a, &b);
            xs.push_back(l);
            xs.push_back(r);
            queries.emplace_back(t, l, r, a, b, -1);
        } else if (t == 1) {
            int64_t p; scanf("%lld", &p);
            xs.push_back(p);
            queries.emplace_back(t, -1, -1, -1, -1, p);
        } else {
            assert (false);
        }
    }

    // construct
    sort(ALL(xs));
    xs.erase(unique(ALL(xs)), xs.end());
    li_chao_tree lichao(xs);

    // output
    for (auto [l, r, a, b] : segments) {
        lichao.add_segment(l, r, a, b);
    }
    for (auto [t, l, r, a, b, p] : queries) {
        if (t == 0) {
            lichao.add_segment(l, r, a, b);
        } else if (t == 1) {
            int64_t q = lichao.get_min(p);
            if (q == INT64_MAX) {
                printf("INFINITY\n");
            } else {
                printf("%lld\n", q);
            }
        } else {
            assert (false);
        }
    }
    return 0;
}
Back to top page