|
| 1 | +#include <algorithm> |
| 2 | +#include <cmath> |
| 3 | +#include <iostream> |
| 4 | +#include <set> |
| 5 | +#include <type_traits> |
| 6 | +#include <vector> |
| 7 | + |
| 8 | +template <typename T> |
| 9 | +struct Point { |
| 10 | + T x, y; |
| 11 | + auto operator<=>(const Point &) const = default; |
| 12 | +}; |
| 13 | +template <typename T, typename U> |
| 14 | +Point<std::common_type_t<T, U>> operator+(Point<T> p1, Point<U> p2) { |
| 15 | + return {p1.x + p2.x, p1.y + p2.y}; |
| 16 | +} |
| 17 | +template <typename T, typename U> |
| 18 | +Point<std::common_type_t<T, U>> operator-(Point<T> p1, Point<U> p2) { |
| 19 | + return {p1.x - p2.x, p1.y - p2.y}; |
| 20 | +} |
| 21 | +template <typename T> |
| 22 | +struct Line { |
| 23 | + Point<T> a, b; |
| 24 | + auto operator<=>(const Line &) const = default; |
| 25 | +}; |
| 26 | +template <typename T> |
| 27 | +T dot(auto p1, auto p2) { |
| 28 | + return (T)p1.x * p2.y - (T)p2.x * p1.y; |
| 29 | +} |
| 30 | +auto arg(auto p) { return std::atan2l(p.y, p.x); } |
| 31 | + |
| 32 | +using fp = long double; |
| 33 | +using i64 = int64_t; |
| 34 | +struct Convex { |
| 35 | + std::set<std::pair<fp, Point<int>>> h{}; |
| 36 | + std::set<std::pair<fp, Line<int>>> t{}; |
| 37 | + Point<fp> m{}; |
| 38 | + |
| 39 | + using Iter = decltype(h)::iterator; |
| 40 | + using IterT = decltype(t)::iterator; |
| 41 | + Iter prev(Iter it) const { |
| 42 | + if (it == h.begin()) it = h.end(); |
| 43 | + return --it; |
| 44 | + } |
| 45 | + IterT prev(IterT it) const { |
| 46 | + if (it == t.begin()) it = t.end(); |
| 47 | + return --it; |
| 48 | + } |
| 49 | + Iter next(Iter it) const { |
| 50 | + if (++it == h.end()) it = h.begin(); |
| 51 | + return it; |
| 52 | + } |
| 53 | + IterT next(IterT it) const { |
| 54 | + if (++it == t.end()) it = t.begin(); |
| 55 | + return it; |
| 56 | + } |
| 57 | + |
| 58 | + auto make_line(Iter it1, Iter it2) { |
| 59 | + const auto &p1 = it1->second; |
| 60 | + const auto &p2 = it2->second; |
| 61 | + return std::make_pair(arg(p2 - p1), Line<int>(p1, p2)); |
| 62 | + } |
| 63 | + void add(Iter it) { |
| 64 | + t.erase(make_line(prev(it), next(it))); |
| 65 | + t.insert(make_line(prev(it), it)); |
| 66 | + t.insert(make_line(it, next(it))); |
| 67 | + } |
| 68 | + void del(Iter it) { |
| 69 | + t.insert(make_line(prev(it), next(it))); |
| 70 | + t.erase(make_line(prev(it), it)); |
| 71 | + t.erase(make_line(it, next(it))); |
| 72 | + } |
| 73 | + |
| 74 | + void init() { |
| 75 | + m = {}; |
| 76 | + for (const auto [_, p] : h) { |
| 77 | + m = m + p; |
| 78 | + } |
| 79 | + m.x /= h.size(); |
| 80 | + m.y /= h.size(); |
| 81 | + |
| 82 | + decltype(h) new_h{}; |
| 83 | + for (const auto [_, p] : h) { |
| 84 | + new_h.emplace(arg(p - m), p); |
| 85 | + } |
| 86 | + h = std::move(new_h); |
| 87 | + |
| 88 | + t.clear(); |
| 89 | + for (auto it = h.begin(); it != h.end(); ++it) { |
| 90 | + t.insert(make_line(it, next(it))); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + void insert(Point<int> p) { |
| 95 | + if (h.size() <= 2) { |
| 96 | + h.emplace(0, p); |
| 97 | + if (h.size() == 3) init(); |
| 98 | + return; |
| 99 | + } |
| 100 | + |
| 101 | + const auto [it, ok] = h.emplace(arg(p - m), p); |
| 102 | + if (!ok) return; |
| 103 | + |
| 104 | + if (dot<i64>(prev(it)->second - p, next(it)->second - p) >= 0) { |
| 105 | + h.erase(it); |
| 106 | + return; |
| 107 | + } |
| 108 | + |
| 109 | + add(it); |
| 110 | + while (h.size() > 3 && dot<i64>(next(it)->second - p, |
| 111 | + next(next(it))->second - p) <= 0) { |
| 112 | + del(next(it)); |
| 113 | + h.erase(next(it)); |
| 114 | + } |
| 115 | + while (h.size() > 3 && dot<i64>(prev(it)->second - p, |
| 116 | + prev(prev(it))->second - p) >= 0) { |
| 117 | + del(prev(it)); |
| 118 | + h.erase(prev(it)); |
| 119 | + } |
| 120 | + } |
| 121 | + |
| 122 | + bool check(int a, int b, i64 c) const { |
| 123 | + auto eval = [a, b, c](Point<int> p) { |
| 124 | + return (i64)a * p.x + (i64)b * p.y - c; |
| 125 | + }; |
| 126 | + |
| 127 | + std::vector<Point<int>> check_list{}; |
| 128 | + if (h.size() <= 8) { |
| 129 | + for (const auto [_, p] : h) check_list.push_back(p); |
| 130 | + } else { |
| 131 | + for (const fp theta : |
| 132 | + {arg(Point<int>{b, -a}), arg(Point<int>{-b, a})}) { |
| 133 | + auto it = t.lower_bound({theta, {}}); |
| 134 | + if (it == t.end()) it = t.begin(); |
| 135 | + check_list.push_back(prev(it)->second.a); |
| 136 | + check_list.push_back(prev(it)->second.b); |
| 137 | + check_list.push_back(next(it)->second.a); |
| 138 | + check_list.push_back(next(it)->second.b); |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + std::vector<i64> res{}; |
| 143 | + for (const auto &p : check_list) { |
| 144 | + res.push_back(eval(p)); |
| 145 | + } |
| 146 | + return std::ranges::max(res) < 0 || std::ranges::min(res) > 0; |
| 147 | + } |
| 148 | +}; |
| 149 | + |
| 150 | +int main() { |
| 151 | + std::ios::sync_with_stdio(false); |
| 152 | + std::cin.tie(nullptr); |
| 153 | + |
| 154 | + int n, q; |
| 155 | + std::cin >> n >> q; |
| 156 | + |
| 157 | + Convex h{}; |
| 158 | + for (int i = 0; i < n; ++i) { |
| 159 | + int x, y; |
| 160 | + std::cin >> x >> y; |
| 161 | + h.insert({x, y}); |
| 162 | + } |
| 163 | + |
| 164 | + while (q--) { |
| 165 | + int op; |
| 166 | + std::cin >> op; |
| 167 | + if (op == 1) { |
| 168 | + int x, y; |
| 169 | + std::cin >> x >> y; |
| 170 | + h.insert({x, y}); |
| 171 | + } else { |
| 172 | + int a, b; |
| 173 | + i64 c; |
| 174 | + std::cin >> a >> b >> c; |
| 175 | + const bool ans = h.check(a, b, c); |
| 176 | + std::cout << (ans ? "YES" : "NO") << '\n'; |
| 177 | + } |
| 178 | + } |
| 179 | +} |
0 commit comments