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/algorithm/dynamic_convex_hull_offline/convex_layers.test.cpp

Depends on

Code

#define PROBLEM "https://judge.yosupo.jp/problem/convex_layers"

#include <cassert>
#include <iostream>
#include <map>

#include "library/algorithm/dynamic_convex_hull_offline.hpp"

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;
    
    std::vector<int> xs(n);
    std::vector<std::pair<int, int>> points(n);
    std::map<std::pair<int, int>, int> id;

    for (int i = 0; i < n; ++i) {
        int x, y;
        std::cin >> x >> y;
        points[i] = { x, y };
        xs[i] = x;
        id[points[i]] = i;
    }

    suisen::DynamicConvexHullOffline hull(xs);
    for (const auto &[x, y] : points) hull.insert(x, y);

    std::vector<int> ans(n);
    int erased = 0;
    for (int i = 1; erased < n; ++i) {
        auto h = hull.get_hull();
        std::sort(h.begin(), h.end());
        assert(std::adjacent_find(h.begin(), h.end(), [&](auto &p, auto &q) { return p == q; }) == h.end());
        for (auto &[x, y] : h) {
            auto it = id.find({ x, y });
            assert(it != id.end());
            ans[it->second] = i;
            ++erased;
            hull.erase(x, y);
            id.erase(it);
        }
    }

    for (const auto &t : ans) {
        assert(t > 0);
        std::cout << t << '\n';
    }

    return 0;
}
#line 1 "test/src/algorithm/dynamic_convex_hull_offline/convex_layers.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/convex_layers"

#include <cassert>
#include <iostream>
#include <map>

#line 1 "library/algorithm/dynamic_convex_hull_offline.hpp"



#include <algorithm>
#include <cstdint>
#include <limits>
#include <set>
#include <tuple>
#include <vector>

namespace suisen {
    struct DynamicConvexHullOffline {
    private:
        static constexpr int64_t inf = std::numeric_limits<int32_t>::max();

        struct Point {
            int64_t x, y;
            Point() = default;
            Point(int64_t x, int64_t y) : x(x), y(y) {}

            bool operator==(const Point& other) const { return x == other.x and y == other.y; }
            bool operator!=(const Point& other) const { return not operator==(other); }

            Point operator+(const Point& other) const { return { x + other.x, y + other.y }; }
            Point operator-(const Point& other) const { return { x - other.x, y - other.y }; }

            operator std::pair<int32_t, int32_t>() const { return { x, y }; }

            friend int64_t det(Point p, Point q) {
                return p.x * q.y - p.y * q.x;
            }
        };

        struct Node {
            std::pair<Point, Point> bridge;
            int64_t min_x;

            Node() = default;
            Node(Point p) : bridge(p, p), min_x(p.x) {}
            Node(std::pair<Point, Point> bridge, int64_t min_x) : bridge(bridge), min_x(min_x) {}

            bool operator==(const Node& other) const { return bridge == other.bridge and min_x == other.min_x; }
            bool operator!=(const Node& other) const { return not operator==(other); }
        };

        static inline const Node None{ Point{ -inf, -inf } };

        int _m;
        std::vector<int32_t> _xs;
        std::vector<std::set<int32_t>> _points_upper;
        std::vector<std::set<int32_t>> _points_lower;

        std::vector<Node> _seg_upper;
        std::vector<Node> _seg_lower;

        static int next_branch(int i, const std::vector<Node>& seg) {
            while (seg[2 * i] == None or seg[2 * i + 1] == None) i = 2 * i + (seg[2 * i] == None);
            return i;
        }

        static Node merge(int x, int y, std::vector<Node>& seg) {
            if (seg[x] == None) return seg[y];
            if (seg[y] == None) return seg[x];

            const int64_t min_x = seg[x].min_x;
            const int64_t sep_x = seg[y].min_x;

            Point a, b, c, d;
            while (true) {
                std::tie(a, b) = seg[x].bridge;
                std::tie(c, d) = seg[y].bridge;
                if (a == b and c == d) break;
                if (a != b and det(b - a, c - a) > 0) {
                    x = 2 * next_branch(x, seg);
                } else if (c != d and det(c - b, d - b) > 0) {
                    y = 2 * next_branch(y, seg) + 1;
                } else if (a == b) {
                    y = 2 * next_branch(y, seg);
                } else if (c == d) {
                    x = 2 * next_branch(x, seg) + 1;
                } else {
                    __int128_t c1 = det(b - a, c - a);
                    __int128_t c2 = det(a - b, d - b);
                    if (c1 + c2 == 0 or c1 * d.x + c2 * c.x < sep_x * (c1 + c2)) {
                        x = 2 * next_branch(x, seg) + 1;
                    } else {
                        y = 2 * next_branch(y, seg);
                    }
                }
            }
            return Node({ a, c }, min_x);
        }

        void set(int32_t i, const Node& dat, std::vector<Node>& seg) {
            seg[_m + i] = dat;
            for (i = (_m + i) >> 1; i > 0; i >>= 1) {
                seg[i] = merge(2 * i, 2 * i + 1, seg);
            }
        }

        void insert(int32_t x, int32_t y, std::vector<Node>& seg, std::vector<std::set<int32_t>>& points) {
            int i = index(x);
            int32_t old_y = seg[_m + i].bridge.first.y;
            points[i].insert(y);
            if (old_y >= y) return;
            set(i, Node{ Point{x, y} }, seg);
        }

        void erase(int32_t x, int32_t y, std::vector<Node>& seg, std::vector<std::set<int32_t>>& points) {
            int i = index(x);
            points[i].erase(y);
            int32_t old_y = seg[_m + i].bridge.first.y;
            if (old_y != y) return;
            set(i, points[i].empty() ? None : Node{ Point{x, *points[i].rbegin()} }, seg);
        }

        static int ceil_pow2(int n) {
            int res = 1;
            while (res < n) res <<= 1;
            return res;
        }

        int index(int32_t x) const {
            return std::lower_bound(_xs.begin(), _xs.end(), x) - _xs.begin();
        }

        int64_t linear_max(int32_t a, int32_t b, const std::vector<Node>& seg) const {
            int64_t res = std::numeric_limits<int64_t>::min();
            for (int k = 1;;) {
                const auto& [p, q] = seg[k].bridge;
                res = std::max(res, p.x * a + p.y * b);
                res = std::max(res, q.x * a + q.y * b);
                if (p == q) break;
                k = 2 * next_branch(k, seg) | ((q.y - p.y) * b >= (q.x - p.x) * -a);
            }
            return res;
        }

        void get_upper_hull(int32_t l, int32_t r, int32_t k, const std::vector<Node>& seg, std::vector<std::pair<int32_t, int32_t>>& res) const {
            if (l > r or seg[k] == None) return;
            if (k >= _m) {
                res.push_back(seg[k].bridge.first);
                return;
            }
            if (seg[2 * k + 0] == None) return get_upper_hull(l, r, 2 * k + 1, seg, res);
            if (seg[2 * k + 1] == None) return get_upper_hull(l, r, 2 * k + 0, seg, res);
            int bl = seg[k].bridge.first.x, br = seg[k].bridge.second.x;
            if (r <= bl) return get_upper_hull(l, r, 2 * k + 0, seg, res);
            if (br <= l) return get_upper_hull(l, r, 2 * k + 1, seg, res);
            get_upper_hull(l, bl, 2 * k + 0, seg, res);
            get_upper_hull(br, r, 2 * k + 1, seg, res);
        }
    public:
        DynamicConvexHullOffline() = default;

        template <typename T>
        DynamicConvexHullOffline(const std::vector<T>& xs) {
            std::copy(xs.begin(), xs.end(), std::back_inserter(_xs));
            std::sort(_xs.begin(), _xs.end());
            _xs.erase(std::unique(_xs.begin(), _xs.end()), _xs.end());
            _m = ceil_pow2(_xs.size());
            _points_upper.resize(_m);
            _points_lower.resize(_m);
            _seg_upper = std::vector<Node>(2 * _m, None);
            _seg_lower = std::vector<Node>(2 * _m, None);
        }

        void insert(int32_t x, int32_t y) {
            insert(x, +y, _seg_upper, _points_upper);
            insert(x, -y, _seg_lower, _points_lower);
        }
        void erase(int32_t x, int32_t y) {
            erase(x, +y, _seg_upper, _points_upper);
            erase(x, -y, _seg_lower, _points_lower);
        }

        // returns max { ax + by | (x, y) in S }
        int64_t linear_max(int32_t a, int32_t b) const {
            return b >= 0 ? linear_max(a, +b, _seg_upper) : linear_max(a, -b, _seg_lower);
        }
        // returns min { ax + by | (x, y) in S }
        int64_t linear_min(int32_t a, int32_t b) const {
            return -linear_max(-a, -b);
        }

        std::vector<std::pair<int32_t, int32_t>> get_upper_hull() const {
            std::vector<std::pair<int32_t, int32_t>> res;
            get_upper_hull(-inf, inf, 1, _seg_upper, res);
            return res;
        }
        std::vector<std::pair<int32_t, int32_t>> get_lower_hull() const {
            std::vector<std::pair<int32_t, int32_t>> res;
            get_upper_hull(-inf, inf, 1, _seg_lower, res);
            for (auto& [x, y] : res) y = -y;
            return res;
        }
        std::vector<std::pair<int32_t, int32_t>> get_hull() const {
            auto upper = get_upper_hull();
            auto lower = get_lower_hull();
            if (upper.empty()) return upper;
            int32_t xl = upper.front().first, xr = upper.back().first;
            int32_t yld = lower.front().second, ylu = upper.front().second;
            int32_t yrd = lower.back().second, yru = upper.back().second;
            lower.erase(std::set_difference(lower.begin(), lower.end(), upper.begin(), upper.end(), lower.begin()), lower.end());
            for (int32_t y : _points_upper[index(xr)]) if (yrd < y and y < yru) lower.emplace_back(xr, y);
            std::reverse(lower.begin(), lower.end());
            for (auto& p : lower) upper.push_back(std::move(p));
            if (xl == xr) return upper;
            for (int32_t y : _points_upper[index(xl)]) if (yld < y and y < ylu) upper.emplace_back(xl, y);
            return upper;
        }
    };
} // namespace suisen



#line 8 "test/src/algorithm/dynamic_convex_hull_offline/convex_layers.test.cpp"

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    std::cin >> n;
    
    std::vector<int> xs(n);
    std::vector<std::pair<int, int>> points(n);
    std::map<std::pair<int, int>, int> id;

    for (int i = 0; i < n; ++i) {
        int x, y;
        std::cin >> x >> y;
        points[i] = { x, y };
        xs[i] = x;
        id[points[i]] = i;
    }

    suisen::DynamicConvexHullOffline hull(xs);
    for (const auto &[x, y] : points) hull.insert(x, y);

    std::vector<int> ans(n);
    int erased = 0;
    for (int i = 1; erased < n; ++i) {
        auto h = hull.get_hull();
        std::sort(h.begin(), h.end());
        assert(std::adjacent_find(h.begin(), h.end(), [&](auto &p, auto &q) { return p == q; }) == h.end());
        for (auto &[x, y] : h) {
            auto it = id.find({ x, y });
            assert(it != id.end());
            ans[it->second] = i;
            ++erased;
            hull.erase(x, y);
            id.erase(it);
        }
    }

    for (const auto &t : ans) {
        assert(t > 0);
        std::cout << t << '\n';
    }

    return 0;
}
Back to top page