CP-Algorithms Library

This documentation is automatically generated by competitive-verifier/competitive-verifier

View the Project on GitHub cp-algorithms/cp-algorithms-aux

:heavy_check_mark: Static Convex Hull (verify/geometry/hull.test.cpp)

Depends on

Code

// @brief Static Convex Hull
#define PROBLEM "https://judge.yosupo.jp/problem/static_convex_hull"
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("tune=native")
#include "cp-algo/geometry/convex_hull.hpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::geometry;
using point = point_t<int64_t>;

void solve() {
    int n;
    cin >> n;
    vector<point> r(n);
    for(auto &it: r) {
        it.read();
    }
    auto res = convex_hull(r);
    cout << size(res) << "\n";
    for(auto it: res) {
        it.print();
    }
}

signed main() {
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    cin >> t;
    while(t--) {
        solve();
    }
}
#line 1 "verify/geometry/hull.test.cpp"
// @brief Static Convex Hull
#define PROBLEM "https://judge.yosupo.jp/problem/static_convex_hull"
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("tune=native")
#line 1 "cp-algo/geometry/convex_hull.hpp"


#line 1 "cp-algo/geometry/point.hpp"


#line 1 "cp-algo/util/complex.hpp"


#include <cmath>
namespace cp_algo {
    // Custom implementation, since std::complex is UB on non-floating types
    template<typename T>
    struct complex {
        using value_type = T;
        T x, y;
        constexpr complex() {}
        constexpr complex(T x): x(x), y(0) {}
        constexpr complex(T x, T y): x(x), y(y) {}
        complex& operator *= (T t) {x *= t; y *= t; return *this;}
        complex& operator /= (T t) {x /= t; y /= t; return *this;}
        complex operator * (T t) const {return complex(*this) *= t;}
        complex operator / (T t) const {return complex(*this) /= t;}
        complex& operator += (complex t) {x += t.x; y += t.y; return *this;}
        complex& operator -= (complex t) {x -= t.x; y -= t.y; return *this;}
        complex operator * (complex t) const {return {x * t.x - y * t.y, x * t.y + y * t.x};}
        complex operator / (complex t) const {return *this * t.conj() / t.norm();}
        complex operator + (complex t) const {return complex(*this) += t;}
        complex operator - (complex t) const {return complex(*this) -= t;}
        complex& operator *= (complex t) {return *this = *this * t;}
        complex& operator /= (complex t) {return *this = *this / t;}
        complex operator - () const {return {-x, -y};}
        complex conj() const {return {x, -y};}
        T norm() const {return x * x + y * y;}
        T abs() const {return std::sqrt(norm());}
        T real() const {return x;}
        T imag() const {return y;}
        T& real() {return x;}
        T& imag() {return y;}
        static complex polar(T r, T theta) {return {r * cos(theta), r * sin(theta)};}
        auto operator <=> (complex const& t) const = default;
    };
    template<typename T>
    complex<T> operator * (auto x, complex<T> y) {return y *= x;}
    template<typename T> complex<T> conj(complex<T> x) {return x.conj();}
    template<typename T> T norm(complex<T> x) {return x.norm();}
    template<typename T> T abs(complex<T> x) {return x.abs();}
    template<typename T> T& real(complex<T> &x) {return x.real();}
    template<typename T> T& imag(complex<T> &x) {return x.imag();}
    template<typename T> T real(complex<T> const& x) {return x.real();}
    template<typename T> T imag(complex<T> const& x) {return x.imag();}
    template<typename T> complex<T> polar(T r, T theta) {return complex<T>::polar(r, theta);}
}

#line 4 "cp-algo/geometry/point.hpp"
#include <iostream>
namespace cp_algo::geometry {
    template<typename ftype>
    struct point_t: complex<ftype> {
        using Base = complex<ftype>;
        using Base::Base;

        point_t(Base const& t): Base(t) {}
        
        auto operator <=> (point_t const& t) const {
            return std::pair{y(), -x()} <=> std::pair{t.y(), -t.x()};
        }

        ftype x() const {return Base::real();}
        ftype y() const {return Base::imag();}

        point_t cmul(point_t const& t) const {return conj(*this) * t;}
        ftype dot(point_t const& t) const {return cmul(t).x();}
        ftype cross(point_t const& t) const {return cmul(t).y();}

        static constexpr point_t O = {0, 0};

        int half() const {
            return *this < O ? -1 : *this == O ? 0 : 1;
        }

        static bool ccw(point_t const& a, point_t const& b) {
            return a.cross(b) > 0;
        }
        static bool ccw_abs(point_t const& a, point_t const & b) {
            return std::tuple{a.half(), (ftype)0, norm(a)} <
                   std::tuple{b.half(), a.cross(b), norm(b)};
        }
        void read() {
            ftype _x, _y;
            std::cin >> _x >> _y;
            *this = {_x, _y};
        }
        void print() const {
            std::cout << x() << ' ' << y() << "\n";
        }
    };
}

#line 4 "cp-algo/geometry/convex_hull.hpp"
#include <algorithm>
#include <utility>
#include <vector>
#include <ranges>
namespace cp_algo::geometry {
    template<typename ftype>
    std::vector<point_t<ftype>> convex_hull(std::vector<point_t<ftype>> r) {
        using point = point_t<ftype>;
        std::ranges::sort(r);
        if(size(r) <= 1 || r[0] == r.back()) {
            return empty(r) ? r : std::vector{r[0]};
        }
        std::vector<point> hull = {r[0]};
        for(int half: {0, 1}) {
            size_t base = size(hull);
            for(auto it: std::views::drop(r, 1)) {
                while(size(hull) >= base + 1) {
                    point a = hull.back();
                    if(point::ccw(it - a, end(hull)[-2] - a)) {
                        break;
                    } else {
                        hull.pop_back();
                    }
                }
                hull.push_back(it);
            }
            std::ranges::reverse(r);
            std::ignore = half;
        }
        hull.pop_back();
        return hull;
    }
}

#line 6 "verify/geometry/hull.test.cpp"
#include <bits/stdc++.h>

using namespace std;
using namespace cp_algo::geometry;
using point = point_t<int64_t>;

void solve() {
    int n;
    cin >> n;
    vector<point> r(n);
    for(auto &it: r) {
        it.read();
    }
    auto res = convex_hull(r);
    cout << size(res) << "\n";
    for(auto it: res) {
        it.print();
    }
}

signed main() {
    //freopen("input.txt", "r", stdin);
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t = 1;
    cin >> t;
    while(t--) {
        solve();
    }
}

Test cases

Env Name Status Elapsed Memory
g++ all_same_00 :heavy_check_mark: AC 70 ms 4 MB
g++ all_same_01 :heavy_check_mark: AC 70 ms 4 MB
g++ example_00 :heavy_check_mark: AC 5 ms 4 MB
g++ example_01 :heavy_check_mark: AC 4 ms 4 MB
g++ max_ans_00 :heavy_check_mark: AC 153 ms 29 MB
g++ max_colinear_00 :heavy_check_mark: AC 112 ms 19 MB
g++ max_colinear_01 :heavy_check_mark: AC 109 ms 19 MB
g++ max_random_00 :heavy_check_mark: AC 120 ms 19 MB
g++ max_random_01 :heavy_check_mark: AC 80 ms 19 MB
g++ max_random_02 :heavy_check_mark: AC 103 ms 19 MB
g++ max_random_03 :heavy_check_mark: AC 111 ms 19 MB
g++ max_random_04 :heavy_check_mark: AC 121 ms 19 MB
g++ max_random_05 :heavy_check_mark: AC 82 ms 19 MB
g++ max_random_06 :heavy_check_mark: AC 103 ms 19 MB
g++ max_random_07 :heavy_check_mark: AC 111 ms 19 MB
g++ near_circle_00 :heavy_check_mark: AC 150 ms 25 MB
g++ near_circle_01 :heavy_check_mark: AC 167 ms 25 MB
g++ small_random_00 :heavy_check_mark: AC 130 ms 4 MB
g++ small_random_01 :heavy_check_mark: AC 95 ms 4 MB
g++ small_random_02 :heavy_check_mark: AC 99 ms 4 MB
g++ small_random_03 :heavy_check_mark: AC 100 ms 4 MB
g++ small_random_04 :heavy_check_mark: AC 127 ms 4 MB
g++ small_random_05 :heavy_check_mark: AC 96 ms 4 MB
g++ small_random_06 :heavy_check_mark: AC 98 ms 4 MB
g++ small_random_07 :heavy_check_mark: AC 103 ms 4 MB
Back to top page