This documentation is automatically generated by NotLeonian/competitive-verifier (forked from competitive-verifier/competitive-verifier)
// competitive-verifier: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
// competitive-verifier: ERROR 0.00001
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>
#include "../geometry/line-convex-polygon-intersection.hpp"
struct Point {
long long x;
long long y;
Point() : x(0), y(0) {}
Point(long long x_, long long y_) : x(x_), y(y_) {}
Point operator+(const Point &other) const {
return Point(x + other.x, y + other.y);
}
Point operator-(const Point &other) const {
return Point(x - other.x, y - other.y);
}
};
struct RealPoint {
long double x;
long double y;
RealPoint() : x(0), y(0) {}
RealPoint(long double x_, long double y_) : x(x_), y(y_) {}
RealPoint operator+(const RealPoint &other) const {
return RealPoint(x + other.x, y + other.y);
}
RealPoint operator-(const RealPoint &other) const {
return RealPoint(x - other.x, y - other.y);
}
RealPoint operator*(long double k) const { return RealPoint(x * k, y * k); }
};
__int128_t cross_value(const Point &a, const Point &b) {
return static_cast<__int128_t>(a.x) * static_cast<__int128_t>(b.y) -
static_cast<__int128_t>(a.y) * static_cast<__int128_t>(b.x);
}
int sign_value(__int128_t x) {
if (x < 0) {
return -1;
}
if (x > 0) {
return 1;
}
return 0;
}
Point read_point() {
long long x, y;
std::cin >> x >> y;
return Point(x, y);
}
RealPoint to_real_point(const Point &p) {
return RealPoint(static_cast<long double>(p.x),
static_cast<long double>(p.y));
}
long double cross_ld(const RealPoint &a, const RealPoint &b) {
return a.x * b.y - a.y * b.x;
}
long double dot_ld(const RealPoint &a, const RealPoint &b) {
return a.x * b.x + a.y * b.y;
}
bool same_point(const RealPoint &a, const RealPoint &b) {
return std::abs(a.x - b.x) <= 1e-12L && std::abs(a.y - b.y) <= 1e-12L;
}
void add_unique(std::vector<RealPoint> &points, const RealPoint &point) {
for (const auto &q : points) {
if (same_point(q, point)) {
return;
}
}
points.push_back(point);
}
RealPoint line_intersection(const Point &line_a, const Point &line_b,
const Point &segment_a, const Point &segment_b) {
const RealPoint u = to_real_point(segment_a);
const RealPoint v = to_real_point(segment_b);
const RealPoint dir = to_real_point(line_b - line_a);
const RealPoint edge = v - u;
const long double denominator = cross_ld(edge, dir);
const long double numerator =
cross_ld(to_real_point(line_a - segment_a), dir);
const long double t = numerator / denominator;
return u + edge * t;
}
std::vector<RealPoint> brute_intersections(const std::vector<Point> &polygon,
const Point &line_a,
const Point &line_b) {
const int n = static_cast<int>(polygon.size());
const Point direction = line_b - line_a;
std::vector<RealPoint> points;
for (int i = 0; i < n; ++i) {
const Point &u = polygon[i];
const Point &v = polygon[(i + 1) % n];
const __int128_t hu = cross_value(u - line_a, direction);
const __int128_t hv = cross_value(v - line_a, direction);
const int su = sign_value(hu);
const int sv = sign_value(hv);
if (su == 0 && sv == 0) {
add_unique(points, to_real_point(u));
add_unique(points, to_real_point(v));
} else if (su == 0) {
add_unique(points, to_real_point(u));
} else if (sv == 0) {
add_unique(points, to_real_point(v));
} else if (su != sv) {
add_unique(points, line_intersection(line_a, line_b, u, v));
}
}
if (points.size() <= 2) {
return points;
}
const RealPoint dir = to_real_point(direction);
int min_index = 0;
int max_index = 0;
for (int i = 1; i < static_cast<int>(points.size()); ++i) {
if (dot_ld(points[i], dir) < dot_ld(points[min_index], dir)) {
min_index = i;
}
if (dot_ld(points[i], dir) > dot_ld(points[max_index], dir)) {
max_index = i;
}
}
return {points[min_index], points[max_index]};
}
std::vector<RealPoint> convex_cut(const std::vector<Point> &polygon,
const Point &line_a, const Point &line_b) {
const int n = static_cast<int>(polygon.size());
const Point direction = line_b - line_a;
std::vector<RealPoint> result;
for (int i = 0; i < n; ++i) {
const Point &now = polygon[i];
const Point &next = polygon[(i + 1) % n];
// AOJ CGL_4_C は有向直線 line_a -> line_b の左側を残す。
const __int128_t current = cross_value(direction, now - line_a);
const __int128_t next_value = cross_value(direction, next - line_a);
if (sign_value(current) >= 0) {
result.push_back(to_real_point(now));
}
if ((current < 0 && next_value > 0) ||
(current > 0 && next_value < 0)) {
result.push_back(line_intersection(line_a, line_b, now, next));
}
}
return result;
}
long double polygon_area(const std::vector<RealPoint> &polygon) {
const int n = static_cast<int>(polygon.size());
long double area = 0;
for (int i = 0; i < n; ++i) {
area += cross_ld(polygon[i], polygon[(i + 1) % n]);
}
return std::abs(area) / 2;
}
std::vector<Point>
remove_collinear_vertices(const std::vector<Point> &polygon) {
const int n = static_cast<int>(polygon.size());
std::vector<Point> result;
result.reserve(n);
for (int i = 0; i < n; ++i) {
const Point &prev = polygon[(i + n - 1) % n];
const Point &cur = polygon[i];
const Point &next = polygon[(i + 1) % n];
if (sign_value(cross_value(cur - prev, next - cur)) == 0) {
continue;
}
result.push_back(cur);
}
assert(result.size() >= 3);
return result;
}
void verify_intersection(const std::vector<Point> &polygon, const Point &line_a,
const Point &line_b) {
const auto fast = line_polygon_intersection(polygon, line_a, line_b);
const auto slow = brute_intersections(polygon, line_a, line_b);
assert(fast.size() == slow.size());
if (fast.empty()) {
return;
}
auto to_real = [](const auto &point) {
return RealPoint(point.template x_as<long double>(),
point.template y_as<long double>());
};
if (fast.size() == 1) {
assert(same_point(to_real(fast[0]), slow[0]));
return;
}
const RealPoint p0 = to_real(fast[0]);
const RealPoint p1 = to_real(fast[1]);
const bool ok = (same_point(p0, slow[0]) && same_point(p1, slow[1])) ||
(same_point(p0, slow[1]) && same_point(p1, slow[0]));
assert(ok);
}
int main() {
int n;
std::cin >> n;
std::vector<Point> polygon(n);
for (auto &p : polygon) {
p = read_point();
}
polygon = remove_collinear_vertices(polygon);
int q;
std::cin >> q;
std::cout << std::fixed << std::setprecision(20);
while (q--) {
const Point line_a = read_point();
const Point line_b = read_point();
verify_intersection(polygon, line_a, line_b);
std::cout << polygon_area(convex_cut(polygon, line_a, line_b)) << '\n';
}
}
#line 1 "verify/aoj-cgl-4-c.test.cpp"
// competitive-verifier: PROBLEM https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
// competitive-verifier: ERROR 0.00001
#include <cassert>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <vector>
#line 1 "geometry/line-convex-polygon-intersection.hpp"
// 反時計回りの面積正の狭義凸多角形と直線の共通部分を求める。
// 共通部分が空集合なら 0 個、1 点なら 1 個、線分ならその端点 2 個を返す。
// 前提: polygon は面積正の狭義凸多角形で、反時計回りで、
// 3 頂点連続で一直線にならず、line_a != line_b。
// 注意: convex_hull の結果が 1 点または 2 点になる退化ケースは前提外。
// 呼び出し側で点または線分として処理すること。
// 座標型が整数なら内部は整数演算で処理し、交点を有理表現で返す。
// 主な対象は 10^9 級制約であり、非常に大きい整数座標、特に 10^18 級では
// 返り値生成時にオーバーフローする可能性がある。
// 計算量 O(log N)。
#line 16 "geometry/line-convex-polygon-intersection.hpp"
#include <complex>
#include <type_traits>
#include <utility>
#line 20 "geometry/line-convex-polygon-intersection.hpp"
namespace line_convex_polygon_intersection_internal {
template <class T> struct is_integral : std::is_integral<T> {};
template <class T> struct is_signed : std::is_signed<T> {};
#ifdef __SIZEOF_INT128__
template <> struct is_integral<__int128_t> : std::true_type {};
template <> struct is_integral<__uint128_t> : std::true_type {};
template <> struct is_signed<__int128_t> : std::true_type {};
template <> struct is_signed<__uint128_t> : std::false_type {};
#endif
template <class T>
using enable_if_integral_t = std::enable_if_t<is_integral<T>::value, int>;
template <class Point, class = void> struct has_member_xy : std::false_type {};
template <class Point>
struct has_member_xy<Point,
std::void_t<decltype(std::declval<const Point &>().x),
decltype(std::declval<const Point &>().y)>>
: std::true_type {};
template <class Point> decltype(auto) get_x(const Point &point) {
if constexpr (has_member_xy<Point>::value) {
return point.x;
} else {
using std::real;
return real(point);
}
}
template <class Point> decltype(auto) get_y(const Point &point) {
if constexpr (has_member_xy<Point>::value) {
return point.y;
} else {
using std::imag;
return imag(point);
}
}
template <class Point>
using coordinate_t =
std::remove_cvref_t<decltype(get_x(std::declval<const Point &>()))>;
template <class T, class = void> struct wide_integer {};
template <class T>
struct wide_integer<
T, std::enable_if_t<is_integral<T>::value && is_signed<T>::value>> {
using type = __int128_t;
};
template <class T>
struct wide_integer<
T, std::enable_if_t<is_integral<T>::value && !is_signed<T>::value>> {
using type = __uint128_t;
};
template <class T> using wide_integer_t = typename wide_integer<T>::type;
template <class Point, bool = is_integral<coordinate_t<Point>>::value>
struct calc_type {
using type = long double;
};
template <class Point> struct calc_type<Point, true> {
using type = wide_integer_t<coordinate_t<Point>>;
};
template <class Point> using calc_t = typename calc_type<Point>::type;
template <class T> int sign_value(const T &value) {
if constexpr (is_integral<T>::value) {
if (value < 0) {
return -1;
}
if (value > 0) {
return 1;
}
return 0;
} else {
constexpr long double eps = 1e-12L;
if (value < -eps) {
return -1;
}
if (value > eps) {
return 1;
}
return 0;
}
}
template <class T> bool equals_value(const T &lhs, const T &rhs) {
return sign_value(lhs - rhs) == 0;
}
template <class Point> calc_t<Point> to_calc_x(const Point &point) {
return static_cast<calc_t<Point>>(get_x(point));
}
template <class Point> calc_t<Point> to_calc_y(const Point &point) {
return static_cast<calc_t<Point>>(get_y(point));
}
template <class Point> calc_t<Point> cross(const Point &lhs, const Point &rhs) {
return to_calc_x(lhs) * to_calc_y(rhs) - to_calc_y(lhs) * to_calc_x(rhs);
}
template <class Point>
Point make_point(const calc_t<Point> &x, const calc_t<Point> &y) {
using Coord = coordinate_t<Point>;
return Point(static_cast<Coord>(x), static_cast<Coord>(y));
}
template <class T, enable_if_integral_t<T> = 0> T abs_value(T value) {
if constexpr (is_signed<T>::value) {
return value < 0 ? -value : value;
} else {
return value;
}
}
template <class T, enable_if_integral_t<T> = 0> T gcd_value(T a, T b) {
a = abs_value(a);
b = abs_value(b);
while (b != 0) {
T t = a % b;
a = b;
b = t;
}
return a;
}
template <class T, enable_if_integral_t<T> = 0> T gcd3_value(T a, T b, T c) {
return gcd_value(gcd_value(a, b), c);
}
template <class Func> int first_non_negative(int length, Func &&func) {
int left = 0;
int right = length;
while (left + 1 < right) {
int mid = (left + right) >> 1;
if (sign_value(func(mid)) < 0) {
left = mid;
} else {
right = mid;
}
}
return right;
}
template <class Func> int last_non_positive(int length, Func &&func) {
int left = 0;
int right = length;
while (left < right) {
int mid = (left + right + 1) >> 1;
if (sign_value(func(mid)) <= 0) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
template <class Func> int last_non_negative(int length, Func &&func) {
int left = 0;
int right = length;
while (left < right) {
int mid = (left + right + 1) >> 1;
if (sign_value(func(mid)) >= 0) {
left = mid;
} else {
right = mid - 1;
}
}
return left;
}
inline int positive_mod(int index, int mod) {
int ret = index % mod;
if (ret < 0) {
ret += mod;
}
return ret;
}
inline int distance_forward(int from, int to, int n) {
if (from <= to) {
return to - from;
}
return to + n - from;
}
template <class Point, class Func>
std::pair<int, int> find_extreme_vertices(int n, Func &&height) {
assert(n >= 3);
int minimum_index = -1;
int maximum_index = -1;
const auto first = height(0);
const auto last = height(n - 1);
if (equals_value(first, last)) {
const auto second = height(1);
if (sign_value(first - second) < 0) {
minimum_index = n - 1;
} else {
maximum_index = n - 1;
}
} else {
const auto second = height(1);
if (sign_value(last - first) > 0 && sign_value(first - second) <= 0) {
minimum_index = 0;
} else if (sign_value(last - first) < 0 &&
sign_value(first - second) >= 0) {
maximum_index = 0;
} else {
const auto denom = static_cast<calc_t<Point>>(n - 1);
auto g_scaled = [&](int index) {
const auto base =
first * static_cast<calc_t<Point>>(n - 1 - index) +
last * static_cast<calc_t<Point>>(index);
const auto value = height(index) * denom;
return sign_value(base - value) < 0 ? base : value;
};
minimum_index = first_non_negative(n - 1, [&](int index) {
return g_scaled(index + 1) - g_scaled(index);
});
}
}
if (maximum_index == -1) {
const int base = minimum_index - n;
const int k = first_non_negative(n, [&](int index) {
return height(base + index) - height(base + index + 1);
});
maximum_index = positive_mod(minimum_index + k, n);
} else {
const int base = maximum_index - n;
const int k = first_non_negative(n, [&](int index) {
return height(base + index + 1) - height(base + index);
});
minimum_index = positive_mod(maximum_index + k, n);
}
return {minimum_index, maximum_index};
}
} // namespace line_convex_polygon_intersection_internal
template <class T> struct LinePolygonIntersectionPoint {
T x_numerator;
T y_numerator;
T denominator;
template <class Real> Real x_as() const {
return static_cast<Real>(x_numerator) / static_cast<Real>(denominator);
}
template <class Real> Real y_as() const {
return static_cast<Real>(y_numerator) / static_cast<Real>(denominator);
}
template <class Point> Point to_point() const {
using Coord =
line_convex_polygon_intersection_internal::coordinate_t<Point>;
if constexpr (line_convex_polygon_intersection_internal::is_integral<
Coord>::value) {
assert(denominator == 1);
return Point(static_cast<Coord>(x_numerator),
static_cast<Coord>(y_numerator));
} else {
return Point(static_cast<Coord>(x_as<long double>()),
static_cast<Coord>(y_as<long double>()));
}
}
};
namespace line_convex_polygon_intersection_internal {
template <class Point, bool = is_integral<coordinate_t<Point>>::value>
struct result_value_type {
using type = Point;
};
template <class Point> struct result_value_type<Point, true> {
using type = LinePolygonIntersectionPoint<calc_t<Point>>;
};
template <class Point>
using result_value_t = typename result_value_type<Point>::type;
} // namespace line_convex_polygon_intersection_internal
template <class Point>
using LinePolygonIntersectionValue =
line_convex_polygon_intersection_internal::result_value_t<Point>;
template <class Point>
using LinePolygonIntersectionResult =
std::vector<LinePolygonIntersectionValue<Point>>;
namespace line_convex_polygon_intersection_internal {
template <class Point>
LinePolygonIntersectionPoint<calc_t<Point>>
make_integral_point(const Point &point) {
using Calc = calc_t<Point>;
return {static_cast<Calc>(get_x(point)), static_cast<Calc>(get_y(point)),
Calc(1)};
}
template <class Point>
LinePolygonIntersectionPoint<calc_t<Point>>
line_edge_intersection_integral(const Point &line_a, const Point &line_b,
const Point &segment_a,
const Point &segment_b) {
using Calc = calc_t<Point>;
const Point direction = line_b - line_a;
const Point edge = segment_b - segment_a;
Calc denominator = cross(edge, direction);
assert(denominator != 0);
Calc numerator = cross(line_a - segment_a, direction);
Calc x_numerator = static_cast<Calc>(get_x(segment_a)) * denominator +
static_cast<Calc>(get_x(edge)) * numerator;
Calc y_numerator = static_cast<Calc>(get_y(segment_a)) * denominator +
static_cast<Calc>(get_y(edge)) * numerator;
if (denominator < 0) {
denominator = -denominator;
x_numerator = -x_numerator;
y_numerator = -y_numerator;
}
const Calc g = gcd3_value(x_numerator, y_numerator, denominator);
if (g != 0) {
x_numerator /= g;
y_numerator /= g;
denominator /= g;
}
return {x_numerator, y_numerator, denominator};
}
template <class Point>
Point line_edge_intersection_floating(const Point &line_a, const Point &line_b,
const Point &segment_a,
const Point &segment_b) {
using Calc = calc_t<Point>;
const Point direction = line_b - line_a;
const Point edge = segment_b - segment_a;
const Calc denominator = cross(edge, direction);
assert(sign_value(denominator) != 0);
const Calc numerator = cross(line_a - segment_a, direction);
const Calc t = numerator / denominator;
const Calc x = static_cast<Calc>(get_x(segment_a)) +
static_cast<Calc>(get_x(edge)) * t;
const Calc y = static_cast<Calc>(get_y(segment_a)) +
static_cast<Calc>(get_y(edge)) * t;
return make_point<Point>(x, y);
}
template <class Point>
result_value_t<Point> make_vertex_result(const Point &point) {
if constexpr (is_integral<coordinate_t<Point>>::value) {
return make_integral_point(point);
} else {
return point;
}
}
template <class Point>
result_value_t<Point> make_edge_result(const Point &line_a, const Point &line_b,
const Point &segment_a,
const Point &segment_b) {
if constexpr (is_integral<coordinate_t<Point>>::value) {
return line_edge_intersection_integral(line_a, line_b, segment_a,
segment_b);
} else {
return line_edge_intersection_floating(line_a, line_b, segment_a,
segment_b);
}
}
} // namespace line_convex_polygon_intersection_internal
template <class Point>
LinePolygonIntersectionResult<Point>
line_polygon_intersection(const std::vector<Point> &polygon,
const Point &line_a, const Point &line_b) {
namespace lpi = line_convex_polygon_intersection_internal;
using Coord = lpi::coordinate_t<Point>;
using Calc = lpi::calc_t<Point>;
static_assert(!lpi::is_integral<Coord>::value ||
lpi::is_signed<Coord>::value,
"integral coordinate type must be signed");
const int n = static_cast<int>(polygon.size());
assert(n >= 3);
assert(!lpi::equals_value(static_cast<Calc>(lpi::get_x(line_a)),
static_cast<Calc>(lpi::get_x(line_b))) ||
!lpi::equals_value(static_cast<Calc>(lpi::get_y(line_a)),
static_cast<Calc>(lpi::get_y(line_b))));
const Point direction = line_b - line_a;
auto vertex = [&](int index) -> const Point & {
return polygon[lpi::positive_mod(index, n)];
};
auto height = [&](int index) -> Calc {
return lpi::cross(vertex(index) - line_a, direction);
};
auto chain_index = [&](int start, int step, int offset) {
return lpi::positive_mod(start + step * offset, n);
};
const auto [minimum_index, maximum_index] =
lpi::find_extreme_vertices<Point>(n, height);
const Calc minimum_value = height(minimum_index);
const Calc maximum_value = height(maximum_index);
LinePolygonIntersectionResult<Point> result;
if (lpi::sign_value(minimum_value) > 0 ||
lpi::sign_value(maximum_value) < 0) {
return result;
}
const int forward_length =
lpi::distance_forward(minimum_index, maximum_index, n);
const int backward_length = n - forward_length;
if (lpi::sign_value(minimum_value) == 0) {
const int forward_zero =
lpi::last_non_positive(forward_length, [&](int offset) {
return height(minimum_index + offset);
});
const int backward_zero =
lpi::last_non_positive(backward_length, [&](int offset) {
return height(minimum_index - offset);
});
const int forward_index = chain_index(minimum_index, +1, forward_zero);
const int backward_index =
chain_index(minimum_index, -1, backward_zero);
result.push_back(lpi::make_vertex_result(vertex(forward_index)));
if (forward_index != backward_index) {
result.push_back(lpi::make_vertex_result(vertex(backward_index)));
}
return result;
}
if (lpi::sign_value(maximum_value) == 0) {
const int forward_length_from_max =
lpi::distance_forward(maximum_index, minimum_index, n);
const int backward_length_from_max = n - forward_length_from_max;
const int forward_zero =
lpi::last_non_negative(forward_length_from_max, [&](int offset) {
return height(maximum_index + offset);
});
const int backward_zero =
lpi::last_non_negative(backward_length_from_max, [&](int offset) {
return height(maximum_index - offset);
});
const int forward_index = chain_index(maximum_index, +1, forward_zero);
const int backward_index =
chain_index(maximum_index, -1, backward_zero);
result.push_back(lpi::make_vertex_result(vertex(forward_index)));
if (forward_index != backward_index) {
result.push_back(lpi::make_vertex_result(vertex(backward_index)));
}
return result;
}
const int first_cross =
lpi::first_non_negative(forward_length, [&](int offset) {
return height(minimum_index + offset);
});
const int first_cross_index = chain_index(minimum_index, +1, first_cross);
if (lpi::sign_value(height(first_cross_index)) == 0) {
result.push_back(lpi::make_vertex_result(vertex(first_cross_index)));
} else {
const int prev_index = chain_index(minimum_index, +1, first_cross - 1);
result.push_back(lpi::make_edge_result(
line_a, line_b, vertex(prev_index), vertex(first_cross_index)));
}
const int second_cross =
lpi::first_non_negative(backward_length, [&](int offset) {
return height(minimum_index - offset);
});
const int second_cross_index = chain_index(minimum_index, -1, second_cross);
if (lpi::sign_value(height(second_cross_index)) == 0) {
result.push_back(lpi::make_vertex_result(vertex(second_cross_index)));
} else {
const int prev_index = chain_index(minimum_index, -1, second_cross - 1);
result.push_back(lpi::make_edge_result(
line_a, line_b, vertex(prev_index), vertex(second_cross_index)));
}
return result;
}
#line 11 "verify/aoj-cgl-4-c.test.cpp"
struct Point {
long long x;
long long y;
Point() : x(0), y(0) {}
Point(long long x_, long long y_) : x(x_), y(y_) {}
Point operator+(const Point &other) const {
return Point(x + other.x, y + other.y);
}
Point operator-(const Point &other) const {
return Point(x - other.x, y - other.y);
}
};
struct RealPoint {
long double x;
long double y;
RealPoint() : x(0), y(0) {}
RealPoint(long double x_, long double y_) : x(x_), y(y_) {}
RealPoint operator+(const RealPoint &other) const {
return RealPoint(x + other.x, y + other.y);
}
RealPoint operator-(const RealPoint &other) const {
return RealPoint(x - other.x, y - other.y);
}
RealPoint operator*(long double k) const { return RealPoint(x * k, y * k); }
};
__int128_t cross_value(const Point &a, const Point &b) {
return static_cast<__int128_t>(a.x) * static_cast<__int128_t>(b.y) -
static_cast<__int128_t>(a.y) * static_cast<__int128_t>(b.x);
}
int sign_value(__int128_t x) {
if (x < 0) {
return -1;
}
if (x > 0) {
return 1;
}
return 0;
}
Point read_point() {
long long x, y;
std::cin >> x >> y;
return Point(x, y);
}
RealPoint to_real_point(const Point &p) {
return RealPoint(static_cast<long double>(p.x),
static_cast<long double>(p.y));
}
long double cross_ld(const RealPoint &a, const RealPoint &b) {
return a.x * b.y - a.y * b.x;
}
long double dot_ld(const RealPoint &a, const RealPoint &b) {
return a.x * b.x + a.y * b.y;
}
bool same_point(const RealPoint &a, const RealPoint &b) {
return std::abs(a.x - b.x) <= 1e-12L && std::abs(a.y - b.y) <= 1e-12L;
}
void add_unique(std::vector<RealPoint> &points, const RealPoint &point) {
for (const auto &q : points) {
if (same_point(q, point)) {
return;
}
}
points.push_back(point);
}
RealPoint line_intersection(const Point &line_a, const Point &line_b,
const Point &segment_a, const Point &segment_b) {
const RealPoint u = to_real_point(segment_a);
const RealPoint v = to_real_point(segment_b);
const RealPoint dir = to_real_point(line_b - line_a);
const RealPoint edge = v - u;
const long double denominator = cross_ld(edge, dir);
const long double numerator =
cross_ld(to_real_point(line_a - segment_a), dir);
const long double t = numerator / denominator;
return u + edge * t;
}
std::vector<RealPoint> brute_intersections(const std::vector<Point> &polygon,
const Point &line_a,
const Point &line_b) {
const int n = static_cast<int>(polygon.size());
const Point direction = line_b - line_a;
std::vector<RealPoint> points;
for (int i = 0; i < n; ++i) {
const Point &u = polygon[i];
const Point &v = polygon[(i + 1) % n];
const __int128_t hu = cross_value(u - line_a, direction);
const __int128_t hv = cross_value(v - line_a, direction);
const int su = sign_value(hu);
const int sv = sign_value(hv);
if (su == 0 && sv == 0) {
add_unique(points, to_real_point(u));
add_unique(points, to_real_point(v));
} else if (su == 0) {
add_unique(points, to_real_point(u));
} else if (sv == 0) {
add_unique(points, to_real_point(v));
} else if (su != sv) {
add_unique(points, line_intersection(line_a, line_b, u, v));
}
}
if (points.size() <= 2) {
return points;
}
const RealPoint dir = to_real_point(direction);
int min_index = 0;
int max_index = 0;
for (int i = 1; i < static_cast<int>(points.size()); ++i) {
if (dot_ld(points[i], dir) < dot_ld(points[min_index], dir)) {
min_index = i;
}
if (dot_ld(points[i], dir) > dot_ld(points[max_index], dir)) {
max_index = i;
}
}
return {points[min_index], points[max_index]};
}
std::vector<RealPoint> convex_cut(const std::vector<Point> &polygon,
const Point &line_a, const Point &line_b) {
const int n = static_cast<int>(polygon.size());
const Point direction = line_b - line_a;
std::vector<RealPoint> result;
for (int i = 0; i < n; ++i) {
const Point &now = polygon[i];
const Point &next = polygon[(i + 1) % n];
// AOJ CGL_4_C は有向直線 line_a -> line_b の左側を残す。
const __int128_t current = cross_value(direction, now - line_a);
const __int128_t next_value = cross_value(direction, next - line_a);
if (sign_value(current) >= 0) {
result.push_back(to_real_point(now));
}
if ((current < 0 && next_value > 0) ||
(current > 0 && next_value < 0)) {
result.push_back(line_intersection(line_a, line_b, now, next));
}
}
return result;
}
long double polygon_area(const std::vector<RealPoint> &polygon) {
const int n = static_cast<int>(polygon.size());
long double area = 0;
for (int i = 0; i < n; ++i) {
area += cross_ld(polygon[i], polygon[(i + 1) % n]);
}
return std::abs(area) / 2;
}
std::vector<Point>
remove_collinear_vertices(const std::vector<Point> &polygon) {
const int n = static_cast<int>(polygon.size());
std::vector<Point> result;
result.reserve(n);
for (int i = 0; i < n; ++i) {
const Point &prev = polygon[(i + n - 1) % n];
const Point &cur = polygon[i];
const Point &next = polygon[(i + 1) % n];
if (sign_value(cross_value(cur - prev, next - cur)) == 0) {
continue;
}
result.push_back(cur);
}
assert(result.size() >= 3);
return result;
}
void verify_intersection(const std::vector<Point> &polygon, const Point &line_a,
const Point &line_b) {
const auto fast = line_polygon_intersection(polygon, line_a, line_b);
const auto slow = brute_intersections(polygon, line_a, line_b);
assert(fast.size() == slow.size());
if (fast.empty()) {
return;
}
auto to_real = [](const auto &point) {
return RealPoint(point.template x_as<long double>(),
point.template y_as<long double>());
};
if (fast.size() == 1) {
assert(same_point(to_real(fast[0]), slow[0]));
return;
}
const RealPoint p0 = to_real(fast[0]);
const RealPoint p1 = to_real(fast[1]);
const bool ok = (same_point(p0, slow[0]) && same_point(p1, slow[1])) ||
(same_point(p0, slow[1]) && same_point(p1, slow[0]));
assert(ok);
}
int main() {
int n;
std::cin >> n;
std::vector<Point> polygon(n);
for (auto &p : polygon) {
p = read_point();
}
polygon = remove_collinear_vertices(polygon);
int q;
std::cin >> q;
std::cout << std::fixed << std::setprecision(20);
while (q--) {
const Point line_a = read_point();
const Point line_b = read_point();
verify_intersection(polygon, line_a, line_b);
std::cout << polygon_area(convex_cut(polygon, line_a, line_b)) << '\n';
}
}
| Env | Name | Status | Elapsed | Memory |
|---|---|---|---|---|
| g++ | 00_sample_00 |
|
2 ms | 4 MB |
| g++ | 01_small_00 |
|
2 ms | 4 MB |
| g++ | 01_small_01 |
|
2 ms | 4 MB |
| g++ | 02_empty_00 |
|
2 ms | 4 MB |
| g++ | 03_general_00 |
|
2 ms | 4 MB |
| g++ | 04_minimum_00 |
|
2 ms | 4 MB |
| g++ | 05_extreme_00 |
|
2 ms | 4 MB |
| g++ | 06_rand_00 |
|
3 ms | 4 MB |
| g++ | 06_rand_01 |
|
3 ms | 4 MB |
| g++ | 06_rand_02 |
|
2 ms | 4 MB |
| g++ | 06_rand_03 |
|
2 ms | 4 MB |
| g++ | 06_rand_04 |
|
3 ms | 4 MB |
| g++ | 06_rand_05 |
|
4 ms | 4 MB |
| g++ | 06_rand_06 |
|
3 ms | 4 MB |
| g++ | 06_rand_07 |
|
3 ms | 4 MB |
| g++ | 07_corner_00 |
|
2 ms | 4 MB |
| clang++ | 00_sample_00 |
|
2 ms | 4 MB |
| clang++ | 01_small_00 |
|
2 ms | 4 MB |
| clang++ | 01_small_01 |
|
2 ms | 4 MB |
| clang++ | 02_empty_00 |
|
2 ms | 4 MB |
| clang++ | 03_general_00 |
|
2 ms | 4 MB |
| clang++ | 04_minimum_00 |
|
2 ms | 4 MB |
| clang++ | 05_extreme_00 |
|
2 ms | 4 MB |
| clang++ | 06_rand_00 |
|
3 ms | 4 MB |
| clang++ | 06_rand_01 |
|
3 ms | 4 MB |
| clang++ | 06_rand_02 |
|
2 ms | 4 MB |
| clang++ | 06_rand_03 |
|
3 ms | 4 MB |
| clang++ | 06_rand_04 |
|
3 ms | 4 MB |
| clang++ | 06_rand_05 |
|
3 ms | 4 MB |
| clang++ | 06_rand_06 |
|
3 ms | 4 MB |
| clang++ | 06_rand_07 |
|
3 ms | 4 MB |
| clang++ | 07_corner_00 |
|
2 ms | 4 MB |