This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub AlexanderNekrasov/Youthful-Passion-Fruit-teambook
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = double;
using ull = unsigned long long;
#define pbc push_back
#define mp make_pair
#define all(a) (a).begin(), (a).end()
#define vin(a) \
for (auto &i : a) \
cin >> i
// mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937 rnd(228);
template <typename T1, typename T2> inline void chkmin(T1 &x, const T2 &y) {
if (y < x) {
x = y;
}
}
template <typename T1, typename T2> inline void chkmax(T1 &x, const T2 &y) {
if (x < y) {
x = y;
}
}
ld EPS = 1e-9;
ld PI = acos(-1);
int sign(ld x) {
if (x > EPS) {
return 1;
} else if (x < -EPS) {
return -1;
} else {
return 0;
}
}
ld sq(ld x) { return x * x; }
struct Point {
ld x = 0, y = 0;
Point() = default;
Point(ld _x, ld _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);
}
Point operator*(const ld &a) const { return Point(x * a, y * a); }
Point operator/(const ld &a) const {
assert(sign(a) != 0);
return Point(x / a, y / a);
}
ld operator^(const Point &other) const { return x * other.y - y * other.x; }
ld operator*(const Point &other) const { return x * other.x + y * other.y; }
Point ort() const { return Point(-y, x); }
ld len2() const { return sq(x) + sq(y); }
ld len() const { return sqrt(len2()); }
int half() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
bool operator<(const Point &other) const {
if (sign(y - other.y) != 0) {
return y < other.y;
} else if (sign(x - other.x) != 0) {
return x < other.x;
} else {
return false;
}
}
bool operator==(Point &other) const {
return sign(x - other.x) == 0 && sign(y - other.y) == 0;
}
Point norm() const {
ld d = len();
// maybe change to if (d == 0) return Point();
assert(sign(d) == 1);
return Point(x / d, y / d);
}
Point turn(ld sin, ld cos) const {
return Point(x * cos - y * sin, x * sin + y * cos);
}
Point turn(ld phi) const { return turn(sin(phi), cos(phi)); }
};
#define Vec Point
ld getAngle(Vec &lhs, Vec &rhs) { return atan2(lhs ^ rhs, lhs * rhs); }
bool cmpHalf(const Vec &lhs, const Vec &rhs) {
if (lhs.half() != rhs.half()) {
return lhs.half();
} else {
int sgn = sign(lhs ^ rhs);
if (!sgn) {
return lhs.len2() < rhs.len2();
} else {
return sgn == 1;
}
}
}
bool isCrossed(ld lx, ld rx, ld ly, ld ry) {
if (lx > rx)
swap(lx, rx);
if (ly > ry)
swap(ly, ry);
return sign(min(rx, ry) - max(lx, ly)) >= 0;
}
// if two segments [a, b] and [c, d] has AT LEAST one common point -> true
bool isCrossed(Point &a, Point &b, Point &c, Point &d) {
if (!isCrossed(a.x, b.x, c.x, d.x))
return false;
if (!isCrossed(a.y, b.y, c.y, d.y))
return false;
Vec v1, v2, v3;
v1 = b - a;
v2 = c - a;
v3 = d - a;
if (sign(v1 ^ v2) * sign(v1 ^ v3) == 1)
return false;
v1 = d - c;
v2 = a - c;
v3 = b - c;
if (sign(v1 ^ v2) * sign(v1 ^ v3) == 1)
return false;
return true;
}
struct Line {
ld a = 0, b = 0, c = 0;
Line() = default;
void norm() {
// for half planes
ld d = Vec(a, b).len();
assert(sign(d) > 0);
a /= d;
b /= d;
c /= d;
}
Line(ld _a, ld _b, ld _c) : a(_a), b(_b), c(_c) { norm(); }
Line(Point x, Point y)
: a(y.y - x.y), b(x.x - y.x), c(x.y * y.x - x.x * y.y) {
norm();
}
ld eval(Point p) const { return a * p.x + b * p.y + c; }
bool isIn(Point p) const { return sign(eval(p)) <= 0; }
bool operator==(const Line &other) const {
return sign(a * other.b - b * other.a) == 0 &&
sign(a * other.c - c * other.a) == 0 &&
sign(b * other.c - c * other.b) == 0;
}
};
ld dist(Line &l, Point &p) { return abs(l.eval(p) / Vec(l.a, l.b).len()); }
/*
x * l.a + y * l.b + l.c = 0
x * m.a + y * m.b + m.c = 0
y * (l.b * m.a - m.b * l.a) + (l.c * m.a - m.c * l.a) = 0
x * m.a + y * m.b + m.c = 0
y = (m.c * l.a - l.c * m.a) / (l.b * m.a - m.b * l.a)
x * l.a + (m.c * l.a - l.c * m.a) / (l.b * m.a - m.b * l.a) * l.b + l.c = 0
x + (m.c * l.b - m.b * l.c) / (l.b * m.a - m.b * l.a) = 0
x = (m.b * l.c - m.c * l.b) / (l.b * m.a - m.b * l.a)
*/
bool cross(Line &l, Line &m, Point &I) {
ld d = l.b * m.a - m.b * l.a;
if (sign(d) == 0) {
return false;
}
ld dx = m.b * l.c - m.c * l.b;
ld dy = m.c * l.a - l.c * m.a;
I = Point(dx / d, dy / d);
return true;
}
int tangents(Point &o, ld r, Point &p, Point &I1, Point &I2) {
ld len = (o - p).len();
int sgn = sign(len - r);
if (sgn == -1) {
return 0;
} else if (sgn == 0) {
I1 = p;
return 1;
} else {
ld x = sq(r) / len;
Vec v = (p - o).norm() * x;
Point a = o + v;
v = (p - o).norm().ort() * sqrt(sq(r) - sq(x));
I1 = a + v;
I2 = a - v;
return 2;
}
}
void tangents(Point c, ld r1, ld r2, vector<Line> &ans) {
ld r = r2 - r1;
ld z = sq(c.x) + sq(c.y);
ld d = z - sq(r);
if (sign(d) == -1)
return;
d = sqrt(abs(d));
Line l;
l.a = (c.x * r + c.y * d) / z;
l.b = (c.y * r - c.x * d) / z;
l.c = r1;
ans.push_back(l);
}
vector<Line> tangents(Point o1, ld r1, Point o2, ld r2) {
vector<Line> ans;
for (int i = -1; i <= 1; i += 2)
for (int j = -1; j <= 1; j += 2)
tangents(o2 - o1, r1 * i, r2 * j, ans);
for (int i = 0; i < (int)ans.size(); ++i)
ans[i].c -= ans[i].a * o1.x + ans[i].b * o1.y;
return ans;
}
int cross(Point o1, ld r1, Point o2, ld r2, Point &I1, Point &I2) {
if (r1 < r2) {
swap(o1, o2);
swap(r1, r2);
}
if (sign(r1 - r2) == 0 && o1 == o2) {
return 3;
}
ld len = (o1 - o2).len();
if (sign(len - r1 - r2) == 1 || sign(r1 - len - r2) == 1) {
return 0;
}
ld d = (sq(r1) - sq(r2) + sq(len)) / 2 / len;
Vec v = (o2 - o1).norm();
Point a = o1 + v * d;
if (sign(len - r1 - r2) == 0 || sign(len + r2 - r1) == 0) {
I1 = a;
return 1;
}
v = v.ort() * sqrt(sq(r1) - sq(d));
I1 = a + v;
I2 = a - v;
return 2;
}
int cross(Point &o, ld r, Line &l, Point &I1, Point &I2) {
ld len = dist(l, o);
int sgn = sign(len - r);
if (sgn == 1) {
return 0;
}
Vec v = Vec(l.a, l.b).norm() * len;
if (sign(l.eval(o + v)) != 0) {
v = Point() - v;
}
Point a = o + v;
if (sgn == 0) {
I1 = a;
return 1;
}
v = Vec(-l.b, l.a).norm() * sqrt(sq(r) - sq(len));
I1 = a + v;
I2 = a - v;
return 2;
}
ld area(vector<Point> &p) {
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
ans += p[i] ^ p[i + 1 < n ? i + 1 : 0];
}
return abs(ans) / 2;
}
ld perimeter(vector<Point> &p) {
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
ans += (p[i] - p[i + 1 < n ? i + 1 : 0]).len();
}
return ans;
}
bool isOnSegment(Point &a, Point &b, Point &x) {
if (a == b) {
return a == x;
}
return sign((b - a) ^ (x - a)) == 0 && sign((b - a) * (x - a)) >= 0 &&
sign((a - b) * (x - b)) >= 0;
// optional (slower, but works better if there are some precision
// problems) return sign((b - a).len() - (x - a).len() - (x - b).len())
// == 0;
}
bool isIn(vector<Point> &p, Point &a) {
int n = p.size();
// depents on limitations
Point b = a + Point(1e9, 1);
int cnt = 0;
for (int i = 0; i < n; ++i) {
Point x = p[i];
Point y = p[i + 1 < n ? i + 1 : 0];
if (isOnSegment(x, y, a)) {
// depends on the problem statement
return true;
}
cnt += isCrossed(x, y, a, b);
}
return cnt % 2 == 1;
/*optional (atan2 is VERY SLOW)!
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
Point x = p[i];
Point y = p[i + 1 < n ? i + 1 : 0];
if (isOnSegment(x, y, a)) {
// depends on the problem statement
return true;
}
x = x - a;
y = y - a;
ans += atan2(x ^ y, x * y);
}
return abs(ans) > 1;*/
}
bool isCounterclockwise(vector<Point> &p) {
int n = p.size();
int pos = min_element(all(p)) - p.begin();
return sign((p[pos + 1 < n ? pos + 1 : 0] - p[pos]) ^
(p[pos - 1 >= 0 ? pos - 1 : n - 1] - p[pos])) == 1;
}
bool isConvex(vector<Point> &p) {
int n = p.size();
int sgn = 0;
for (int i = 0; i < n; ++i) {
int cur_sgn = sign((p[i - 1 >= 0 ? i - 1 : n - 1] - p[i]) ^
(p[i + 1 < n ? i + 1 : 0] - p[i]));
if (sgn && sgn != cur_sgn) {
return false;
}
sgn = cur_sgn;
}
return true;
}
bool isInTriangle(Point &a, Point &b, Point &c, Point &x) {
return sign((b - a) ^ (x - a)) >= 0 && sign((c - b) ^ (x - b)) >= 0 &&
sign((a - c) ^ (x - c)) >= 0;
}
// points should be in the counterclockwise order
bool isInConvex(vector<Point> &p, Point &a) {
int n = p.size();
assert(n >= 3);
// assert(isConvex(p));
// assert(isCounterclockwise(p));
if (sign((p[1] - p[0]) ^ (a - p[0])) < 0)
return false;
if (sign((p[n - 1] - p[0]) ^ (a - p[0])) > 0)
return false;
int pos = lower_bound(p.begin() + 2, p.end(), a,
[&](Point lhs, Point rhs) -> bool {
return sign((lhs - p[0]) ^ (rhs - p[0])) > 0;
}) -
p.begin();
assert(pos > 1 && pos < n);
return isInTriangle(p[0], p[pos - 1], p[pos], a);
}
vector<Point> convexHull(vector<Point> p) {
if (p.empty()) {
return {};
}
int n = p.size();
int pos = min_element(all(p)) - p.begin();
swap(p[0], p[pos]);
for (int i = 1; i < n; ++i)
p[i] = p[i] - p[0];
sort(p.begin() + 1, p.end(), [&](Point &lhs, Point &rhs) -> bool {
int sgn = sign(lhs ^ rhs);
if (!sgn) {
return lhs.len2() < rhs.len2();
}
return sgn == 1;
});
for (int i = 1; i < n; ++i)
p[i] = p[i] + p[0];
int top = 0;
for (int i = 0; i < n; ++i) {
while (top >= 2) {
Vec v1 = p[top - 1] - p[top - 2];
Vec v2 = p[i] - p[top - 1];
if (sign(v1 ^ v2) == 1)
break;
--top;
}
p[top++] = p[i];
}
p.resize(top);
return p;
}
Vec getPoint(Line l) { return Vec(-l.b, l.a); }
bool bad(Line a, Line b, Line c) {
Point x;
assert(cross(b, c, x) == 1);
return a.eval(x) > 0;
}
// Do not forget about the bounding box
vector<Point> hpi(vector<Line> lines) {
sort(all(lines), [](Line al, Line bl) -> bool {
Point a = getPoint(al);
Point b = getPoint(bl);
if (a.y >= 0 && b.y < 0)
return 1;
if (a.y < 0 && b.y >= 0)
return 0;
if (a.y == 0 && b.y == 0)
return a.x > 0 && b.x < 0;
return (a ^ b) > 0;
});
vector<pair<Line, int>> st;
for (int it = 0; it < 2; it++) {
for (int i = 0; i < (int)lines.size(); i++) {
bool flag = false;
while (!st.empty()) {
if ((getPoint(st.back().first) - getPoint(lines[i])).len() <
EPS) {
if (lines[i].c <= st.back().first.c) {
flag = true;
break;
} else {
st.pop_back();
}
} else if ((getPoint(st.back().first) ^ getPoint(lines[i])) <
EPS / 2) {
return {};
} else if (st.size() >= 2 &&
bad(st[st.size() - 2].first, st[st.size() - 1].first,
lines[i])) {
st.pop_back();
} else {
break;
}
}
if (!flag)
st.push_back({lines[i], i});
}
}
vector<int> en(lines.size(), -1);
vector<Point> ans;
for (int i = 0; i < (int)st.size(); i++) {
if (en[st[i].second] == -1) {
en[st[i].second] = i;
continue;
}
for (int j = en[st[i].second]; j < i; j++) {
Point I;
assert(cross(st[j].first, st[j + 1].first, I) == 1);
ans.push_back(I);
}
break;
}
return ans;
}
bool isHpiEmpty(vector<Line> lines) {
// return hpi(lines).empty();
// overflow/precision problems?
shuffle(all(lines), rnd);
const ld C = 1e9;
Point ans(C, C);
vector<Point> box = {{-C, -C}, {C, -C}, {C, C}, {-C, C}};
for (int i = 0; i < 4; ++i)
lines.push_back({box[i], box[(i + 1) % 4]});
int n = lines.size();
for (int i = n - 4; i >= 0; --i) {
if (lines[i].isIn(ans))
continue;
Point up(0, C + 1), down(0, -C - 1), pi = getPoint(lines[i]);
for (int j = i + 1; j < n; ++j) {
if (lines[i] == lines[j])
continue;
Point p, pj = getPoint(lines[j]);
if (!cross(lines[i], lines[j], p)) {
if (sign(pi * pj) != -1)
continue;
if (sign(lines[i].c + lines[j].c) *
(!sign(pi.y) ? sign(pi.x) : -1) ==
-1)
return true;
} else {
if ((!sign(pi.y) ? sign(pi.x) : sign(pi.y)) * (sign(pi ^ pj)) ==
1)
chkmin(up, p);
else
chkmax(down, p);
}
}
if ((ans = up) < down)
return true;
}
// for (int i = 0; i < n; ++i) {
// assert(lines[i].eval(ans) < EPS);
// }
return false;
}
ld diameter(vector<Point> p) {
p = convexHull(p);
int n = p.size();
if (n <= 1) {
return 0;
}
if (n == 2) {
return (p[0] - p[1]).len();
}
ld ans = 0;
int i = 0, j = 1;
while (i < n) {
while (sign((p[(i + 1) % n] - p[i]) ^ (p[(j + 1) % n] - p[j])) >= 0) {
chkmax(ans, (p[i] - p[j]).len());
j = (j + 1) % n;
}
chkmax(ans, (p[i] - p[j]).len());
++i;
}
return ans;
}
pair<int, int> tangents_alex(vector<Point> &p, Point &a) {
int n = p.size();
int l = __lg(n);
auto findWithSign = [&](int val) {
int i = 0;
for (int k = l; k >= 0; --k) {
int i1 = (i - (1 << k) + n) % n;
int i2 = (i + (1 << k)) % n;
if (sign((p[i1] - a) ^ (p[i] - a)) == val)
i = i1;
if (sign((p[i2] - a) ^ (p[i] - a)) == val)
i = i2;
}
return i;
};
return {findWithSign(1), findWithSign(-1)};
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.precision(20), cout.setf(ios::fixed);
// Tinkoff Generation 2021-2022. C. Геометрия 1 A - Площадь треугольника
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
cout << abs((b - a) ^ (c - a)) / 2 << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 B - Угол между векторами
/*{
Vec a, b;
cin >> a.x >> a.y >> b.x >> b.y;
cout << abs(getAngle(a, b)) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 C - Точка в углу
/*{
Point a, o, b, p;
cin >> a.x >> a.y >> o.x >> o.y >> b.x >> b.y >> p.x >> p.y;
a = a - o;
b = b - o;
if (sign(a ^ b) <= 0) {
swap(a, b);
}
p = p - o;
bool ok = true;
if (sign(a ^ b) == 1) {
ok = sign(a ^ p) >= 0 && sign(p ^ b) >= 0;
} else {
ok = !(sign(a ^ p) < 0 && sign(p ^ b) < 0);
}
if (ok) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 D - Пересечение отрезков
/*{
Point a, b, c, d;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y;
if (isCrossed(a, b, c, d)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 E - Расстояние от точки
// до прямой
/*{
Point p;
cin >> p.x >> p.y;
Line l;
cin >> l.a >> l.b >> l.c;
cout << dist(l, p) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 F - Пересечение прямых
/*{
Point a, b, c, d;
Line l, m;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y;
l = Line(a, b);
m = Line(c, d);
Point ans;
if (cross(l, m, ans)) {
cout << 1 << " " << ans.x << " " << ans.y << endl;
} else if (l == m) {
cout << 2 << endl;
} else {
cout << 0 << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 G - Пусти козла в
// огород~- 1
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
auto calc = [](Vec lhs, Vec rhs) -> ld {
ld sgn = sign(lhs ^ rhs);
if (!sgn) {
return 180;
}
if (sgn < 0) {
swap(lhs, rhs);
}
return atan2(lhs ^ rhs, lhs * rhs) / (2 * PI) * 360;
};
cout << max({calc(b - a, c - a), calc(c - b, a - b), calc(a - c, b -
c)}) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 H - Биссектриса
/*{
Point x, y, z;
cin >> x.x >> x.y >> y.x >> y.y >> z.x >> z.y;
y = (y - x).norm();
z = (z - x).norm();
Line l(x, x + y + z);
cout << l.a << " " << l.b << " " << l.c << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 I - Пусти козла в огород
// - 4
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
Vec v1, v2;
v1 = (b - a).norm();
v2 = (c - a).norm();
Line l(a, a + v1 + v2);
v1 = (a - b).norm();
v2 = (c - b).norm();
Line m(b, b + v1 + v2);
Point ans;
if (cross(l, m, ans)) {
cout << ans.x << " " << ans.y << endl;
} else {
assert(false);
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 A - Касательные к
// окружности
/*{
Point o, p;
ld r;
cin >> o.x >> o.y >> r >> p.x >> p.y;
Point I1, I2;
int ans = tangents(o, r, p, I1, I2);
if (!ans) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
cout << ans << "\n" << I1.x << " " << I1.y << "\n" << I2.x << " " <<
I2.y << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 B - Пересекаем окружности
/*{
int t;
cin >> t;
while (t--) {
Point o1, o2;
ld r1, r2;
cin >> o1.x >> o1.y >> r1 >> o2.x >> o2.y >> r2;
Point I1, I2;
int ans = cross(o1, r1, o2, r2, I1, I2);
if (!ans || ans == 3) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
Point fans = (I1 + I2) / 2;
cout << ans << "\n"
<< fans.x << " " << fans.y << "\n"
<< (o1 - fans).len() << " " << (I1 - fans).len() << "\n"
<< I1.x << " " << I1.y << "\n"
<< I2.x << " " << I2.y << endl;
}
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 C - Прямая и окружность
/*{
Point o;
ld r;
Line l;
cin >> o.x >> o.y >> r >> l.a >> l.b >> l.c;
Point I1, I2;
int ans = cross(o, r, l, I1, I2);
if (!ans) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
cout << ans << "\n" << I1.x << " " << I1.y << "\n" << I2.x << " " <<
I2.y << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 D - Площадь
// многоугольника
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
ld ans = area(p);
cout << (ll)(ans) << (sign(ans - (ll)ans) == 1 ? ".5" : "") << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 E - Точка в
// многоугольнике
/*{
#ifndef LOCAL
freopen("point.in", "r", stdin);
freopen("point.out", "w", stdout);
#endif
int n;
cin >> n;
Point a;
cin >> a.x >> a.y;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (isIn(p, a)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 F - Выпукл ли
// многоугольник
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (isConvex(p)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 G - Теодор Рузвельт
/*{
int n, m, k;
cin >> n >> m >> k;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
assert(isConvex(p));
assert(isCounterclockwise(p));
int cnt = 0;
for (int i = 0; i < m; ++i) {
Point a;
cin >> a.x >> a.y;
if (isInConvex(p, a)) {
++cnt;
}
}
if (cnt >= k) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 B - Замок
/*{
int n;
cin >> n;
vector<vector<Point>> p(n);
vector<ld> areas(n);
for (int i = 0; i < n; ++i) {
int k;
cin >> k;
p[i].resize(k);
for (auto& [x, y] : p[i]) {
cin >> x >> y;
}
areas[i] = area(p[i]);
}
vector<int> order(n);
iota(all(order), 0);
sort(all(order), [&](int lhs, int rhs) -> bool { return areas[lhs] <
areas[rhs]; }); vector<bool> used(n); int q; cin >> q; for (int i = 0; i
< q; ++i) { Point a; cin >> a.x >> a.y; int L = -1, R = n; while (L < R -
1) { int M = (L + R) / 2; if (isInConvex(p[order[M]], a)) { R = M; } else
{ L = M;
}
}
if (R < n)
used[R] = true;
}
ld ans = 0;
for (int i = 0; i < n; ++i) {
if (used[i]) {
ans += areas[order[i]] - (i > 0 ? areas[order[i - 1]] : 0);
}
}
cout << ans << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 D - Выпуклая оболочка
/*{
#ifndef LOCAL
freopen("hull.in", "r", stdin);
freopen("hull.out", "w", stdout);
#endif
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
p = convexHull(p);
cout << p.size() << '\n';
for (auto& [x, y] : p) {
cout << (ll)(round(x)) << " " << (ll)(round(y)) << '\n';
}
ld ans = area(p);
cout << (ll)(ans) << (sign(ans - (ll)ans) == 1 ? ".5" : "") << endl;
}*/
// Stress tangents, fast point location
/* {
int N = 100000;
int C = 1e9;
int Q = 100;
auto get = [&] (int l, int r) -> int {
return (ull)rnd() % (r - l + 1) + l;
};
auto stupidTangents = [&] (vector<Point>& p, Point& a) {
auto cmp = [&](Point& lhs, Point& rhs) -> bool {
return sign((lhs - a) ^ (rhs - a)) > 0;
};
int posL = min_element(all(p), cmp) - p.begin();
int posR = max_element(all(p), cmp) - p.begin();
return mp(posL, posR);
};
for (int test_id = 0; test_id < 1'000'000; ++test_id) {
int n = get(1, N);
vector<Point> p(n);
for (int i = 0; i < n; ++i) {
p[i] = Point(get(-C, C), get(-C, C));
}
p = convexHull(p);
n = p.size();
for (int i = 0; i < Q; ++i) {
Point a(-C, C);
if (p.size() >= 3) {
if(isInConvex(p, a) != isIn(p, a)) {
cerr << "WA convex " << test_id << " " << i << endl;
cerr << "n = " << n << endl;
cerr << "p = " << endl;
for (auto [x, y] : p) {
cerr << "(" << x << ", " << y << ")" << endl;
}
cerr << "a = " << endl;
cerr << "(" << a.x << " " << a.y << ")" << endl;
cerr << "ans = " << isIn(p, a) << endl;
cerr << "out = " << isInConvex(p, a) << endl;
exit(1);
}
}
if (isIn(p, a)) continue;
auto ans = stupidTangents(p, a);
auto out = tangents_alex(p, a);
bool ok = true;
if (sign((p[ans.first] - a) ^ (p[out.first] - a)) != 0) {
ok = false;
} else if (sign((p[ans.second] - a) ^ (p[out.second] - a)) != 0) {
ok = false;
}
if (!ok) {
cerr << "WA tangents " << test_id << " " << i << endl;
cerr << "n = " << n << endl;
cerr << "p = " << endl;
for (auto [x, y] : p) {
cerr << "(" << x << ", " << y << ")" << endl;
}
cerr << "a = " << endl;
cerr << "(" << a.x << " " << a.y << ")" << endl;
cerr << "ans = " << ans.first << " " << ans.second << endl;
cerr << "out = " << out.first << " " << out.second << endl;
exit(1);
}
}
cerr << "OK " << test_id << endl;
}
} */
// Tinkoff Generation 2021-2022. B'. Геометрия C - Сыр (Offlin + check
// Online tangents)
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
p = convexHull(p);
n = p.size();
int m;
cin >> m;
vector<Point> pIn(m);
for (auto& [x, y] : pIn) {
cin >> x >> y;
}
pIn = convexHull(pIn);
m = pIn.size();
Point base = p[0];
auto cmp = [&](Point& lhs, Point& rhs) -> bool {
return sign((lhs - base) ^ (rhs - base)) > 0;
};
int posL = min_element(all(pIn), cmp) - pIn.begin();
int nxtL = 1;
auto nxtV = [](int v, int n) -> int { return v + 1 < n ? v + 1 : 0; };
auto moveL = [&]() {
while (cmp(pIn[nxtV(posL, m)], pIn[posL])) posL = nxtV(posL, m);
assert(sign((pIn[posL] - base) ^ (pIn[tangents_alex(pIn, base).first]
- base)) == 0); while (cmp(p[nxtV(nxtL, n)], pIn[posL])) nxtL =
nxtV(nxtL, n);
};
int posR = max_element(all(pIn), cmp) - pIn.begin();
int nxtR = 0;
auto moveR = [&]() {
while (cmp(pIn[posR], pIn[nxtV(posR, m)])) posR = nxtV(posR, m);
assert(sign((pIn[posR] - base) ^ (pIn[tangents_alex(pIn,
base).second] - base)) == 0); while (!cmp(pIn[posR], p[nxtR])) nxtR =
nxtV(nxtR, n);
};
vector<ll> prefArea(n);
for (int i = 2; i < n; ++i) {
prefArea[i] = abs(round((p[i - 1] - p[0]) ^ (p[i] - p[0])));
prefArea[i] += prefArea[i - 1];
}
auto calcArea = [&](int l, int r) -> ll {
ll fans;
if (l <= r) {
if (r - l < 2) return 0;
fans = prefArea[r] - prefArea[l] - abs(round((p[l] - p[0]) ^ (p[r]
- p[0]))); } else { fans = prefArea[n - 1] - prefArea[l] + prefArea[r] +
abs(round((p[l] - p[0]) ^ (p[r] - p[0])));
}
return fans;
};
ll ans = 0;
for (int i = 0; i < n; ++i) {
base = p[i];
moveL();
moveR();
chkmax(ans, calcArea(i, nxtL));
chkmax(ans, calcArea(nxtR, i));
}
cout << ans << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 E - Разрезание торта
/*{
#ifndef LOCAL
freopen("cut.in", "r", stdin);
freopen("cut.out", "w", stdout);
#endif
ld C = 1e3 + 228;
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (!isCounterclockwise(p)) {
reverse(all(p));
}
ld need = area(p) / 2;
auto calc1 = [&](ld x) -> ld {
vector<Point> has;
Point D(x, -C);
Point U(x, C);
Line l(D, U);
for (int i = 0; i < n; ++i) {
if (p[i].x < x) {
has.push_back(p[i]);
}
Point cur = p[i];
Point nxt = p[i + 1 < n ? i + 1 : 0];
if (sign(cur.x - nxt.x) != 0) {
if (!isCrossed(D, U, cur, nxt))
continue;
Point I;
assert(cross(l, Line(cur, nxt), I) == 1);
has.push_back(I);
}
}
return area(convexHull(has));
};
auto calc2 = [&](ld x) -> ld {
Point D(x, -C);
Point U(x, C);
Line l(D, U);
vector<Line> lines;
for (int i = 0; i < n; ++i) {
lines.emplace_back(p[i], p[i + 1 < n ? i + 1 : 0]);
}
lines.push_back(l);
return area(hpi(lines));
};
ld L = -C, R = C;
for (int it = 0; it < 60; ++it) {
ld M = (L + R) / 2;
assert(sign(calc1(M) - calc2(M)) == 0);
if (calc1(M) < need) {
L = M;
} else {
R = M;
}
}
cout << R << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 H - Две самые далёкие
// точки
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
cout << diameter(p) << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 K - Стена
/*{
#ifndef LOCAL
freopen("wall.in", "r", stdin);
freopen("wall.out", "w", stdout);
#endif
int n, l;
cin >> n >> l;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
ld ans = perimeter(convexHull(p)) + 2 * PI * l;
cout << ans << endl;
}*/
// Stress isHpiEmpty, hpi
{
int N = 10;
int C = 10;
auto get = [&](int l, int r) -> int {
return (ull)rnd() % (r - l + 1) + l;
};
auto getPoint = [&]() -> Point {
return Point(get(-C, C), get(-C, C));
};
for (int test_id = 0;; ++test_id) {
int n = get(1, N);
vector<Line> lines(n);
for (int i = 0; i < n; ++i) {
Point a = getPoint();
Point b = getPoint();
while (a == b) {
b = getPoint();
}
lines[i] = {a, b};
}
// cerr << "n = " << n << endl;
// cerr << "lines = " << endl;
// for (auto [a, b, c] : lines) {
// cerr << "x * " << a << " + y * " << b << " + " << c << " = 0"
// << endl;
// }
const ld C = 1e9;
vector<Point> box = {{-C, -C}, {C, -C}, {C, C}, {-C, C}};
for (int i = 0; i < 4; ++i) {
lines.push_back({box[i], box[(i + 1) % 4]});
}
bool ans = hpi(lines).empty();
lines.resize(n);
bool out = isHpiEmpty(lines);
if (ans == 0 && out == 1) {
cerr << "WA isHpiEmpty " << test_id << endl;
cerr << "n = " << n << endl;
cerr << "lines = " << endl;
for (auto [a, b, c] : lines) {
cerr << "x * " << a << " + y * " << b << " + " << c
<< " = 0" << endl;
}
cerr << "ans = " << ans << endl;
cerr << "out = " << out << endl;
exit(1);
}
cerr << "OK " << test_id << " ans = " << ans << endl;
}
}
// 2021-2022 ICPC NERC (NEERC), North-Western Russia Regional Contest
// (Northern Subregionals) G https://codeforces.com/gym/104011/problem/G
/* {
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
int pos = min_element(all(p)) - p.begin();
rotate(p.begin(), p.begin() + pos, p.end());
vector<Point> v;
for (int i = 0; i < n; ++i) {
v.push_back(p[i + 1 < n ? i + 1 : 0] - p[i]);
}
vector<int> fpos(n);
for (int i = 0; i < n; ++i) {
int pos = lower_bound(all(v), Point() - v[i], cmpHalf) - v.begin();
pos = pos % n;
fpos[i] = pos;
}
auto check = [&](ld x) -> bool {
vector<Line> lines;
lines.reserve(2 * n);
auto addLine = [&](int i, int j) {
Vec v1 = (p[j] - p[i]) * (x / (x + 1));
Vec v2 = (p[j + 1 < n ? j + 1 : 0] - p[i]) * (x / (x + 1));
lines.push_back({p[i] + v1, p[i] + v2});
};
for (int i = 0; i < n; ++i) {
int pos = fpos[i];
addLine(i, pos);
addLine(pos, i);
}
return !isHpiEmpty(lines);
};
ld L = 1, R = 2;
for (int it = 0; it < 19; ++it) {
ld M = sqrt(L * R);
if (check(M)) {
R = M;
} else {
L = M;
}
}
cout << sqrt(L * R) << endl;
} */
return 0;
}
#line 1 "geometry/geometry.cpp"
#ifdef LOCAL
#define _GLIBCXX_DEBUG
#endif
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = double;
using ull = unsigned long long;
#define pbc push_back
#define mp make_pair
#define all(a) (a).begin(), (a).end()
#define vin(a) \
for (auto &i : a) \
cin >> i
// mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
mt19937 rnd(228);
template <typename T1, typename T2> inline void chkmin(T1 &x, const T2 &y) {
if (y < x) {
x = y;
}
}
template <typename T1, typename T2> inline void chkmax(T1 &x, const T2 &y) {
if (x < y) {
x = y;
}
}
ld EPS = 1e-9;
ld PI = acos(-1);
int sign(ld x) {
if (x > EPS) {
return 1;
} else if (x < -EPS) {
return -1;
} else {
return 0;
}
}
ld sq(ld x) { return x * x; }
struct Point {
ld x = 0, y = 0;
Point() = default;
Point(ld _x, ld _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);
}
Point operator*(const ld &a) const { return Point(x * a, y * a); }
Point operator/(const ld &a) const {
assert(sign(a) != 0);
return Point(x / a, y / a);
}
ld operator^(const Point &other) const { return x * other.y - y * other.x; }
ld operator*(const Point &other) const { return x * other.x + y * other.y; }
Point ort() const { return Point(-y, x); }
ld len2() const { return sq(x) + sq(y); }
ld len() const { return sqrt(len2()); }
int half() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
bool operator<(const Point &other) const {
if (sign(y - other.y) != 0) {
return y < other.y;
} else if (sign(x - other.x) != 0) {
return x < other.x;
} else {
return false;
}
}
bool operator==(Point &other) const {
return sign(x - other.x) == 0 && sign(y - other.y) == 0;
}
Point norm() const {
ld d = len();
// maybe change to if (d == 0) return Point();
assert(sign(d) == 1);
return Point(x / d, y / d);
}
Point turn(ld sin, ld cos) const {
return Point(x * cos - y * sin, x * sin + y * cos);
}
Point turn(ld phi) const { return turn(sin(phi), cos(phi)); }
};
#define Vec Point
ld getAngle(Vec &lhs, Vec &rhs) { return atan2(lhs ^ rhs, lhs * rhs); }
bool cmpHalf(const Vec &lhs, const Vec &rhs) {
if (lhs.half() != rhs.half()) {
return lhs.half();
} else {
int sgn = sign(lhs ^ rhs);
if (!sgn) {
return lhs.len2() < rhs.len2();
} else {
return sgn == 1;
}
}
}
bool isCrossed(ld lx, ld rx, ld ly, ld ry) {
if (lx > rx)
swap(lx, rx);
if (ly > ry)
swap(ly, ry);
return sign(min(rx, ry) - max(lx, ly)) >= 0;
}
// if two segments [a, b] and [c, d] has AT LEAST one common point -> true
bool isCrossed(Point &a, Point &b, Point &c, Point &d) {
if (!isCrossed(a.x, b.x, c.x, d.x))
return false;
if (!isCrossed(a.y, b.y, c.y, d.y))
return false;
Vec v1, v2, v3;
v1 = b - a;
v2 = c - a;
v3 = d - a;
if (sign(v1 ^ v2) * sign(v1 ^ v3) == 1)
return false;
v1 = d - c;
v2 = a - c;
v3 = b - c;
if (sign(v1 ^ v2) * sign(v1 ^ v3) == 1)
return false;
return true;
}
struct Line {
ld a = 0, b = 0, c = 0;
Line() = default;
void norm() {
// for half planes
ld d = Vec(a, b).len();
assert(sign(d) > 0);
a /= d;
b /= d;
c /= d;
}
Line(ld _a, ld _b, ld _c) : a(_a), b(_b), c(_c) { norm(); }
Line(Point x, Point y)
: a(y.y - x.y), b(x.x - y.x), c(x.y * y.x - x.x * y.y) {
norm();
}
ld eval(Point p) const { return a * p.x + b * p.y + c; }
bool isIn(Point p) const { return sign(eval(p)) <= 0; }
bool operator==(const Line &other) const {
return sign(a * other.b - b * other.a) == 0 &&
sign(a * other.c - c * other.a) == 0 &&
sign(b * other.c - c * other.b) == 0;
}
};
ld dist(Line &l, Point &p) { return abs(l.eval(p) / Vec(l.a, l.b).len()); }
/*
x * l.a + y * l.b + l.c = 0
x * m.a + y * m.b + m.c = 0
y * (l.b * m.a - m.b * l.a) + (l.c * m.a - m.c * l.a) = 0
x * m.a + y * m.b + m.c = 0
y = (m.c * l.a - l.c * m.a) / (l.b * m.a - m.b * l.a)
x * l.a + (m.c * l.a - l.c * m.a) / (l.b * m.a - m.b * l.a) * l.b + l.c = 0
x + (m.c * l.b - m.b * l.c) / (l.b * m.a - m.b * l.a) = 0
x = (m.b * l.c - m.c * l.b) / (l.b * m.a - m.b * l.a)
*/
bool cross(Line &l, Line &m, Point &I) {
ld d = l.b * m.a - m.b * l.a;
if (sign(d) == 0) {
return false;
}
ld dx = m.b * l.c - m.c * l.b;
ld dy = m.c * l.a - l.c * m.a;
I = Point(dx / d, dy / d);
return true;
}
int tangents(Point &o, ld r, Point &p, Point &I1, Point &I2) {
ld len = (o - p).len();
int sgn = sign(len - r);
if (sgn == -1) {
return 0;
} else if (sgn == 0) {
I1 = p;
return 1;
} else {
ld x = sq(r) / len;
Vec v = (p - o).norm() * x;
Point a = o + v;
v = (p - o).norm().ort() * sqrt(sq(r) - sq(x));
I1 = a + v;
I2 = a - v;
return 2;
}
}
void tangents(Point c, ld r1, ld r2, vector<Line> &ans) {
ld r = r2 - r1;
ld z = sq(c.x) + sq(c.y);
ld d = z - sq(r);
if (sign(d) == -1)
return;
d = sqrt(abs(d));
Line l;
l.a = (c.x * r + c.y * d) / z;
l.b = (c.y * r - c.x * d) / z;
l.c = r1;
ans.push_back(l);
}
vector<Line> tangents(Point o1, ld r1, Point o2, ld r2) {
vector<Line> ans;
for (int i = -1; i <= 1; i += 2)
for (int j = -1; j <= 1; j += 2)
tangents(o2 - o1, r1 * i, r2 * j, ans);
for (int i = 0; i < (int)ans.size(); ++i)
ans[i].c -= ans[i].a * o1.x + ans[i].b * o1.y;
return ans;
}
int cross(Point o1, ld r1, Point o2, ld r2, Point &I1, Point &I2) {
if (r1 < r2) {
swap(o1, o2);
swap(r1, r2);
}
if (sign(r1 - r2) == 0 && o1 == o2) {
return 3;
}
ld len = (o1 - o2).len();
if (sign(len - r1 - r2) == 1 || sign(r1 - len - r2) == 1) {
return 0;
}
ld d = (sq(r1) - sq(r2) + sq(len)) / 2 / len;
Vec v = (o2 - o1).norm();
Point a = o1 + v * d;
if (sign(len - r1 - r2) == 0 || sign(len + r2 - r1) == 0) {
I1 = a;
return 1;
}
v = v.ort() * sqrt(sq(r1) - sq(d));
I1 = a + v;
I2 = a - v;
return 2;
}
int cross(Point &o, ld r, Line &l, Point &I1, Point &I2) {
ld len = dist(l, o);
int sgn = sign(len - r);
if (sgn == 1) {
return 0;
}
Vec v = Vec(l.a, l.b).norm() * len;
if (sign(l.eval(o + v)) != 0) {
v = Point() - v;
}
Point a = o + v;
if (sgn == 0) {
I1 = a;
return 1;
}
v = Vec(-l.b, l.a).norm() * sqrt(sq(r) - sq(len));
I1 = a + v;
I2 = a - v;
return 2;
}
ld area(vector<Point> &p) {
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
ans += p[i] ^ p[i + 1 < n ? i + 1 : 0];
}
return abs(ans) / 2;
}
ld perimeter(vector<Point> &p) {
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
ans += (p[i] - p[i + 1 < n ? i + 1 : 0]).len();
}
return ans;
}
bool isOnSegment(Point &a, Point &b, Point &x) {
if (a == b) {
return a == x;
}
return sign((b - a) ^ (x - a)) == 0 && sign((b - a) * (x - a)) >= 0 &&
sign((a - b) * (x - b)) >= 0;
// optional (slower, but works better if there are some precision
// problems) return sign((b - a).len() - (x - a).len() - (x - b).len())
// == 0;
}
bool isIn(vector<Point> &p, Point &a) {
int n = p.size();
// depents on limitations
Point b = a + Point(1e9, 1);
int cnt = 0;
for (int i = 0; i < n; ++i) {
Point x = p[i];
Point y = p[i + 1 < n ? i + 1 : 0];
if (isOnSegment(x, y, a)) {
// depends on the problem statement
return true;
}
cnt += isCrossed(x, y, a, b);
}
return cnt % 2 == 1;
/*optional (atan2 is VERY SLOW)!
ld ans = 0;
int n = p.size();
for (int i = 0; i < n; ++i) {
Point x = p[i];
Point y = p[i + 1 < n ? i + 1 : 0];
if (isOnSegment(x, y, a)) {
// depends on the problem statement
return true;
}
x = x - a;
y = y - a;
ans += atan2(x ^ y, x * y);
}
return abs(ans) > 1;*/
}
bool isCounterclockwise(vector<Point> &p) {
int n = p.size();
int pos = min_element(all(p)) - p.begin();
return sign((p[pos + 1 < n ? pos + 1 : 0] - p[pos]) ^
(p[pos - 1 >= 0 ? pos - 1 : n - 1] - p[pos])) == 1;
}
bool isConvex(vector<Point> &p) {
int n = p.size();
int sgn = 0;
for (int i = 0; i < n; ++i) {
int cur_sgn = sign((p[i - 1 >= 0 ? i - 1 : n - 1] - p[i]) ^
(p[i + 1 < n ? i + 1 : 0] - p[i]));
if (sgn && sgn != cur_sgn) {
return false;
}
sgn = cur_sgn;
}
return true;
}
bool isInTriangle(Point &a, Point &b, Point &c, Point &x) {
return sign((b - a) ^ (x - a)) >= 0 && sign((c - b) ^ (x - b)) >= 0 &&
sign((a - c) ^ (x - c)) >= 0;
}
// points should be in the counterclockwise order
bool isInConvex(vector<Point> &p, Point &a) {
int n = p.size();
assert(n >= 3);
// assert(isConvex(p));
// assert(isCounterclockwise(p));
if (sign((p[1] - p[0]) ^ (a - p[0])) < 0)
return false;
if (sign((p[n - 1] - p[0]) ^ (a - p[0])) > 0)
return false;
int pos = lower_bound(p.begin() + 2, p.end(), a,
[&](Point lhs, Point rhs) -> bool {
return sign((lhs - p[0]) ^ (rhs - p[0])) > 0;
}) -
p.begin();
assert(pos > 1 && pos < n);
return isInTriangle(p[0], p[pos - 1], p[pos], a);
}
vector<Point> convexHull(vector<Point> p) {
if (p.empty()) {
return {};
}
int n = p.size();
int pos = min_element(all(p)) - p.begin();
swap(p[0], p[pos]);
for (int i = 1; i < n; ++i)
p[i] = p[i] - p[0];
sort(p.begin() + 1, p.end(), [&](Point &lhs, Point &rhs) -> bool {
int sgn = sign(lhs ^ rhs);
if (!sgn) {
return lhs.len2() < rhs.len2();
}
return sgn == 1;
});
for (int i = 1; i < n; ++i)
p[i] = p[i] + p[0];
int top = 0;
for (int i = 0; i < n; ++i) {
while (top >= 2) {
Vec v1 = p[top - 1] - p[top - 2];
Vec v2 = p[i] - p[top - 1];
if (sign(v1 ^ v2) == 1)
break;
--top;
}
p[top++] = p[i];
}
p.resize(top);
return p;
}
Vec getPoint(Line l) { return Vec(-l.b, l.a); }
bool bad(Line a, Line b, Line c) {
Point x;
assert(cross(b, c, x) == 1);
return a.eval(x) > 0;
}
// Do not forget about the bounding box
vector<Point> hpi(vector<Line> lines) {
sort(all(lines), [](Line al, Line bl) -> bool {
Point a = getPoint(al);
Point b = getPoint(bl);
if (a.y >= 0 && b.y < 0)
return 1;
if (a.y < 0 && b.y >= 0)
return 0;
if (a.y == 0 && b.y == 0)
return a.x > 0 && b.x < 0;
return (a ^ b) > 0;
});
vector<pair<Line, int>> st;
for (int it = 0; it < 2; it++) {
for (int i = 0; i < (int)lines.size(); i++) {
bool flag = false;
while (!st.empty()) {
if ((getPoint(st.back().first) - getPoint(lines[i])).len() <
EPS) {
if (lines[i].c <= st.back().first.c) {
flag = true;
break;
} else {
st.pop_back();
}
} else if ((getPoint(st.back().first) ^ getPoint(lines[i])) <
EPS / 2) {
return {};
} else if (st.size() >= 2 &&
bad(st[st.size() - 2].first, st[st.size() - 1].first,
lines[i])) {
st.pop_back();
} else {
break;
}
}
if (!flag)
st.push_back({lines[i], i});
}
}
vector<int> en(lines.size(), -1);
vector<Point> ans;
for (int i = 0; i < (int)st.size(); i++) {
if (en[st[i].second] == -1) {
en[st[i].second] = i;
continue;
}
for (int j = en[st[i].second]; j < i; j++) {
Point I;
assert(cross(st[j].first, st[j + 1].first, I) == 1);
ans.push_back(I);
}
break;
}
return ans;
}
bool isHpiEmpty(vector<Line> lines) {
// return hpi(lines).empty();
// overflow/precision problems?
shuffle(all(lines), rnd);
const ld C = 1e9;
Point ans(C, C);
vector<Point> box = {{-C, -C}, {C, -C}, {C, C}, {-C, C}};
for (int i = 0; i < 4; ++i)
lines.push_back({box[i], box[(i + 1) % 4]});
int n = lines.size();
for (int i = n - 4; i >= 0; --i) {
if (lines[i].isIn(ans))
continue;
Point up(0, C + 1), down(0, -C - 1), pi = getPoint(lines[i]);
for (int j = i + 1; j < n; ++j) {
if (lines[i] == lines[j])
continue;
Point p, pj = getPoint(lines[j]);
if (!cross(lines[i], lines[j], p)) {
if (sign(pi * pj) != -1)
continue;
if (sign(lines[i].c + lines[j].c) *
(!sign(pi.y) ? sign(pi.x) : -1) ==
-1)
return true;
} else {
if ((!sign(pi.y) ? sign(pi.x) : sign(pi.y)) * (sign(pi ^ pj)) ==
1)
chkmin(up, p);
else
chkmax(down, p);
}
}
if ((ans = up) < down)
return true;
}
// for (int i = 0; i < n; ++i) {
// assert(lines[i].eval(ans) < EPS);
// }
return false;
}
ld diameter(vector<Point> p) {
p = convexHull(p);
int n = p.size();
if (n <= 1) {
return 0;
}
if (n == 2) {
return (p[0] - p[1]).len();
}
ld ans = 0;
int i = 0, j = 1;
while (i < n) {
while (sign((p[(i + 1) % n] - p[i]) ^ (p[(j + 1) % n] - p[j])) >= 0) {
chkmax(ans, (p[i] - p[j]).len());
j = (j + 1) % n;
}
chkmax(ans, (p[i] - p[j]).len());
++i;
}
return ans;
}
pair<int, int> tangents_alex(vector<Point> &p, Point &a) {
int n = p.size();
int l = __lg(n);
auto findWithSign = [&](int val) {
int i = 0;
for (int k = l; k >= 0; --k) {
int i1 = (i - (1 << k) + n) % n;
int i2 = (i + (1 << k)) % n;
if (sign((p[i1] - a) ^ (p[i] - a)) == val)
i = i1;
if (sign((p[i2] - a) ^ (p[i] - a)) == val)
i = i2;
}
return i;
};
return {findWithSign(1), findWithSign(-1)};
}
signed main() {
cin.tie(0)->sync_with_stdio(0);
cout.precision(20), cout.setf(ios::fixed);
// Tinkoff Generation 2021-2022. C. Геометрия 1 A - Площадь треугольника
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
cout << abs((b - a) ^ (c - a)) / 2 << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 B - Угол между векторами
/*{
Vec a, b;
cin >> a.x >> a.y >> b.x >> b.y;
cout << abs(getAngle(a, b)) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 C - Точка в углу
/*{
Point a, o, b, p;
cin >> a.x >> a.y >> o.x >> o.y >> b.x >> b.y >> p.x >> p.y;
a = a - o;
b = b - o;
if (sign(a ^ b) <= 0) {
swap(a, b);
}
p = p - o;
bool ok = true;
if (sign(a ^ b) == 1) {
ok = sign(a ^ p) >= 0 && sign(p ^ b) >= 0;
} else {
ok = !(sign(a ^ p) < 0 && sign(p ^ b) < 0);
}
if (ok) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 D - Пересечение отрезков
/*{
Point a, b, c, d;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y;
if (isCrossed(a, b, c, d)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 E - Расстояние от точки
// до прямой
/*{
Point p;
cin >> p.x >> p.y;
Line l;
cin >> l.a >> l.b >> l.c;
cout << dist(l, p) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 F - Пересечение прямых
/*{
Point a, b, c, d;
Line l, m;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> d.x >> d.y;
l = Line(a, b);
m = Line(c, d);
Point ans;
if (cross(l, m, ans)) {
cout << 1 << " " << ans.x << " " << ans.y << endl;
} else if (l == m) {
cout << 2 << endl;
} else {
cout << 0 << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 G - Пусти козла в
// огород~- 1
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
auto calc = [](Vec lhs, Vec rhs) -> ld {
ld sgn = sign(lhs ^ rhs);
if (!sgn) {
return 180;
}
if (sgn < 0) {
swap(lhs, rhs);
}
return atan2(lhs ^ rhs, lhs * rhs) / (2 * PI) * 360;
};
cout << max({calc(b - a, c - a), calc(c - b, a - b), calc(a - c, b -
c)}) << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 H - Биссектриса
/*{
Point x, y, z;
cin >> x.x >> x.y >> y.x >> y.y >> z.x >> z.y;
y = (y - x).norm();
z = (z - x).norm();
Line l(x, x + y + z);
cout << l.a << " " << l.b << " " << l.c << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 1 I - Пусти козла в огород
// - 4
/*{
Point a, b, c;
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y;
Vec v1, v2;
v1 = (b - a).norm();
v2 = (c - a).norm();
Line l(a, a + v1 + v2);
v1 = (a - b).norm();
v2 = (c - b).norm();
Line m(b, b + v1 + v2);
Point ans;
if (cross(l, m, ans)) {
cout << ans.x << " " << ans.y << endl;
} else {
assert(false);
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 A - Касательные к
// окружности
/*{
Point o, p;
ld r;
cin >> o.x >> o.y >> r >> p.x >> p.y;
Point I1, I2;
int ans = tangents(o, r, p, I1, I2);
if (!ans) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
cout << ans << "\n" << I1.x << " " << I1.y << "\n" << I2.x << " " <<
I2.y << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 B - Пересекаем окружности
/*{
int t;
cin >> t;
while (t--) {
Point o1, o2;
ld r1, r2;
cin >> o1.x >> o1.y >> r1 >> o2.x >> o2.y >> r2;
Point I1, I2;
int ans = cross(o1, r1, o2, r2, I1, I2);
if (!ans || ans == 3) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
Point fans = (I1 + I2) / 2;
cout << ans << "\n"
<< fans.x << " " << fans.y << "\n"
<< (o1 - fans).len() << " " << (I1 - fans).len() << "\n"
<< I1.x << " " << I1.y << "\n"
<< I2.x << " " << I2.y << endl;
}
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 C - Прямая и окружность
/*{
Point o;
ld r;
Line l;
cin >> o.x >> o.y >> r >> l.a >> l.b >> l.c;
Point I1, I2;
int ans = cross(o, r, l, I1, I2);
if (!ans) {
cout << ans << endl;
} else if (ans == 1) {
cout << ans << "\n" << I1.x << " " << I1.y << endl;
} else if (ans == 2) {
cout << ans << "\n" << I1.x << " " << I1.y << "\n" << I2.x << " " <<
I2.y << endl;
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 D - Площадь
// многоугольника
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
ld ans = area(p);
cout << (ll)(ans) << (sign(ans - (ll)ans) == 1 ? ".5" : "") << endl;
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 E - Точка в
// многоугольнике
/*{
#ifndef LOCAL
freopen("point.in", "r", stdin);
freopen("point.out", "w", stdout);
#endif
int n;
cin >> n;
Point a;
cin >> a.x >> a.y;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (isIn(p, a)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 F - Выпукл ли
// многоугольник
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (isConvex(p)) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. C. Геометрия 2 G - Теодор Рузвельт
/*{
int n, m, k;
cin >> n >> m >> k;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
assert(isConvex(p));
assert(isCounterclockwise(p));
int cnt = 0;
for (int i = 0; i < m; ++i) {
Point a;
cin >> a.x >> a.y;
if (isInConvex(p, a)) {
++cnt;
}
}
if (cnt >= k) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 B - Замок
/*{
int n;
cin >> n;
vector<vector<Point>> p(n);
vector<ld> areas(n);
for (int i = 0; i < n; ++i) {
int k;
cin >> k;
p[i].resize(k);
for (auto& [x, y] : p[i]) {
cin >> x >> y;
}
areas[i] = area(p[i]);
}
vector<int> order(n);
iota(all(order), 0);
sort(all(order), [&](int lhs, int rhs) -> bool { return areas[lhs] <
areas[rhs]; }); vector<bool> used(n); int q; cin >> q; for (int i = 0; i
< q; ++i) { Point a; cin >> a.x >> a.y; int L = -1, R = n; while (L < R -
1) { int M = (L + R) / 2; if (isInConvex(p[order[M]], a)) { R = M; } else
{ L = M;
}
}
if (R < n)
used[R] = true;
}
ld ans = 0;
for (int i = 0; i < n; ++i) {
if (used[i]) {
ans += areas[order[i]] - (i > 0 ? areas[order[i - 1]] : 0);
}
}
cout << ans << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 D - Выпуклая оболочка
/*{
#ifndef LOCAL
freopen("hull.in", "r", stdin);
freopen("hull.out", "w", stdout);
#endif
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
p = convexHull(p);
cout << p.size() << '\n';
for (auto& [x, y] : p) {
cout << (ll)(round(x)) << " " << (ll)(round(y)) << '\n';
}
ld ans = area(p);
cout << (ll)(ans) << (sign(ans - (ll)ans) == 1 ? ".5" : "") << endl;
}*/
// Stress tangents, fast point location
/* {
int N = 100000;
int C = 1e9;
int Q = 100;
auto get = [&] (int l, int r) -> int {
return (ull)rnd() % (r - l + 1) + l;
};
auto stupidTangents = [&] (vector<Point>& p, Point& a) {
auto cmp = [&](Point& lhs, Point& rhs) -> bool {
return sign((lhs - a) ^ (rhs - a)) > 0;
};
int posL = min_element(all(p), cmp) - p.begin();
int posR = max_element(all(p), cmp) - p.begin();
return mp(posL, posR);
};
for (int test_id = 0; test_id < 1'000'000; ++test_id) {
int n = get(1, N);
vector<Point> p(n);
for (int i = 0; i < n; ++i) {
p[i] = Point(get(-C, C), get(-C, C));
}
p = convexHull(p);
n = p.size();
for (int i = 0; i < Q; ++i) {
Point a(-C, C);
if (p.size() >= 3) {
if(isInConvex(p, a) != isIn(p, a)) {
cerr << "WA convex " << test_id << " " << i << endl;
cerr << "n = " << n << endl;
cerr << "p = " << endl;
for (auto [x, y] : p) {
cerr << "(" << x << ", " << y << ")" << endl;
}
cerr << "a = " << endl;
cerr << "(" << a.x << " " << a.y << ")" << endl;
cerr << "ans = " << isIn(p, a) << endl;
cerr << "out = " << isInConvex(p, a) << endl;
exit(1);
}
}
if (isIn(p, a)) continue;
auto ans = stupidTangents(p, a);
auto out = tangents_alex(p, a);
bool ok = true;
if (sign((p[ans.first] - a) ^ (p[out.first] - a)) != 0) {
ok = false;
} else if (sign((p[ans.second] - a) ^ (p[out.second] - a)) != 0) {
ok = false;
}
if (!ok) {
cerr << "WA tangents " << test_id << " " << i << endl;
cerr << "n = " << n << endl;
cerr << "p = " << endl;
for (auto [x, y] : p) {
cerr << "(" << x << ", " << y << ")" << endl;
}
cerr << "a = " << endl;
cerr << "(" << a.x << " " << a.y << ")" << endl;
cerr << "ans = " << ans.first << " " << ans.second << endl;
cerr << "out = " << out.first << " " << out.second << endl;
exit(1);
}
}
cerr << "OK " << test_id << endl;
}
} */
// Tinkoff Generation 2021-2022. B'. Геометрия C - Сыр (Offlin + check
// Online tangents)
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
p = convexHull(p);
n = p.size();
int m;
cin >> m;
vector<Point> pIn(m);
for (auto& [x, y] : pIn) {
cin >> x >> y;
}
pIn = convexHull(pIn);
m = pIn.size();
Point base = p[0];
auto cmp = [&](Point& lhs, Point& rhs) -> bool {
return sign((lhs - base) ^ (rhs - base)) > 0;
};
int posL = min_element(all(pIn), cmp) - pIn.begin();
int nxtL = 1;
auto nxtV = [](int v, int n) -> int { return v + 1 < n ? v + 1 : 0; };
auto moveL = [&]() {
while (cmp(pIn[nxtV(posL, m)], pIn[posL])) posL = nxtV(posL, m);
assert(sign((pIn[posL] - base) ^ (pIn[tangents_alex(pIn, base).first]
- base)) == 0); while (cmp(p[nxtV(nxtL, n)], pIn[posL])) nxtL =
nxtV(nxtL, n);
};
int posR = max_element(all(pIn), cmp) - pIn.begin();
int nxtR = 0;
auto moveR = [&]() {
while (cmp(pIn[posR], pIn[nxtV(posR, m)])) posR = nxtV(posR, m);
assert(sign((pIn[posR] - base) ^ (pIn[tangents_alex(pIn,
base).second] - base)) == 0); while (!cmp(pIn[posR], p[nxtR])) nxtR =
nxtV(nxtR, n);
};
vector<ll> prefArea(n);
for (int i = 2; i < n; ++i) {
prefArea[i] = abs(round((p[i - 1] - p[0]) ^ (p[i] - p[0])));
prefArea[i] += prefArea[i - 1];
}
auto calcArea = [&](int l, int r) -> ll {
ll fans;
if (l <= r) {
if (r - l < 2) return 0;
fans = prefArea[r] - prefArea[l] - abs(round((p[l] - p[0]) ^ (p[r]
- p[0]))); } else { fans = prefArea[n - 1] - prefArea[l] + prefArea[r] +
abs(round((p[l] - p[0]) ^ (p[r] - p[0])));
}
return fans;
};
ll ans = 0;
for (int i = 0; i < n; ++i) {
base = p[i];
moveL();
moveR();
chkmax(ans, calcArea(i, nxtL));
chkmax(ans, calcArea(nxtR, i));
}
cout << ans << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 E - Разрезание торта
/*{
#ifndef LOCAL
freopen("cut.in", "r", stdin);
freopen("cut.out", "w", stdout);
#endif
ld C = 1e3 + 228;
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
if (!isCounterclockwise(p)) {
reverse(all(p));
}
ld need = area(p) / 2;
auto calc1 = [&](ld x) -> ld {
vector<Point> has;
Point D(x, -C);
Point U(x, C);
Line l(D, U);
for (int i = 0; i < n; ++i) {
if (p[i].x < x) {
has.push_back(p[i]);
}
Point cur = p[i];
Point nxt = p[i + 1 < n ? i + 1 : 0];
if (sign(cur.x - nxt.x) != 0) {
if (!isCrossed(D, U, cur, nxt))
continue;
Point I;
assert(cross(l, Line(cur, nxt), I) == 1);
has.push_back(I);
}
}
return area(convexHull(has));
};
auto calc2 = [&](ld x) -> ld {
Point D(x, -C);
Point U(x, C);
Line l(D, U);
vector<Line> lines;
for (int i = 0; i < n; ++i) {
lines.emplace_back(p[i], p[i + 1 < n ? i + 1 : 0]);
}
lines.push_back(l);
return area(hpi(lines));
};
ld L = -C, R = C;
for (int it = 0; it < 60; ++it) {
ld M = (L + R) / 2;
assert(sign(calc1(M) - calc2(M)) == 0);
if (calc1(M) < need) {
L = M;
} else {
R = M;
}
}
cout << R << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 H - Две самые далёкие
// точки
/*{
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
cout << diameter(p) << endl;
}*/
// Tinkoff Generation 2021-2022. B'. Геометрия 2 K - Стена
/*{
#ifndef LOCAL
freopen("wall.in", "r", stdin);
freopen("wall.out", "w", stdout);
#endif
int n, l;
cin >> n >> l;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
ld ans = perimeter(convexHull(p)) + 2 * PI * l;
cout << ans << endl;
}*/
// Stress isHpiEmpty, hpi
{
int N = 10;
int C = 10;
auto get = [&](int l, int r) -> int {
return (ull)rnd() % (r - l + 1) + l;
};
auto getPoint = [&]() -> Point {
return Point(get(-C, C), get(-C, C));
};
for (int test_id = 0;; ++test_id) {
int n = get(1, N);
vector<Line> lines(n);
for (int i = 0; i < n; ++i) {
Point a = getPoint();
Point b = getPoint();
while (a == b) {
b = getPoint();
}
lines[i] = {a, b};
}
// cerr << "n = " << n << endl;
// cerr << "lines = " << endl;
// for (auto [a, b, c] : lines) {
// cerr << "x * " << a << " + y * " << b << " + " << c << " = 0"
// << endl;
// }
const ld C = 1e9;
vector<Point> box = {{-C, -C}, {C, -C}, {C, C}, {-C, C}};
for (int i = 0; i < 4; ++i) {
lines.push_back({box[i], box[(i + 1) % 4]});
}
bool ans = hpi(lines).empty();
lines.resize(n);
bool out = isHpiEmpty(lines);
if (ans == 0 && out == 1) {
cerr << "WA isHpiEmpty " << test_id << endl;
cerr << "n = " << n << endl;
cerr << "lines = " << endl;
for (auto [a, b, c] : lines) {
cerr << "x * " << a << " + y * " << b << " + " << c
<< " = 0" << endl;
}
cerr << "ans = " << ans << endl;
cerr << "out = " << out << endl;
exit(1);
}
cerr << "OK " << test_id << " ans = " << ans << endl;
}
}
// 2021-2022 ICPC NERC (NEERC), North-Western Russia Regional Contest
// (Northern Subregionals) G https://codeforces.com/gym/104011/problem/G
/* {
int n;
cin >> n;
vector<Point> p(n);
for (auto& [x, y] : p) {
cin >> x >> y;
}
int pos = min_element(all(p)) - p.begin();
rotate(p.begin(), p.begin() + pos, p.end());
vector<Point> v;
for (int i = 0; i < n; ++i) {
v.push_back(p[i + 1 < n ? i + 1 : 0] - p[i]);
}
vector<int> fpos(n);
for (int i = 0; i < n; ++i) {
int pos = lower_bound(all(v), Point() - v[i], cmpHalf) - v.begin();
pos = pos % n;
fpos[i] = pos;
}
auto check = [&](ld x) -> bool {
vector<Line> lines;
lines.reserve(2 * n);
auto addLine = [&](int i, int j) {
Vec v1 = (p[j] - p[i]) * (x / (x + 1));
Vec v2 = (p[j + 1 < n ? j + 1 : 0] - p[i]) * (x / (x + 1));
lines.push_back({p[i] + v1, p[i] + v2});
};
for (int i = 0; i < n; ++i) {
int pos = fpos[i];
addLine(i, pos);
addLine(pos, i);
}
return !isHpiEmpty(lines);
};
ld L = 1, R = 2;
for (int it = 0; it < 19; ++it) {
ld M = sqrt(L * R);
if (check(M)) {
R = M;
} else {
L = M;
}
}
cout << sqrt(L * R) << endl;
} */
return 0;
}