Open neal2018 opened 3 years ago
tuple<int, int, ld> closest_pair(vector<Point> &p) {
using Pt = pair<Point, int>;
int n = p.size();
assert(n > 1);
vector<Pt> pts(n), buf;
for (int i = 0; i < n; i++) pts[i] = {p[i], i};
sort(pts.begin(), pts.end());
buf.reserve(n);
auto cmp_y = [](const Pt &p1, const Pt &p2) { return p1.first.y < p2.first.y; };
function<tuple<int, int, ld>(int, int)> recurse = [&](int l, int r) {
int i = pts[l].second, j = pts[l + 1].second;
ld d = dist(pts[l].first, pts[l + 1].first);
if (r - l < 5) {
for (int a = l; a < r; a++)
for (int b = a + 1; b < r; b++) {
ld cur = dist(pts[a].first, pts[b].first);
if (cur < d) i = pts[a].second, j = pts[b].second, d = cur;
}
sort(pts.begin() + l, pts.begin() + r, cmp_y);
} else {
int mid = (l + r) / 2;
ld x = pts[mid].first.x;
auto [li, lj, ldist] = recurse(l, mid);
auto [ri, rj, rdist] = recurse(mid, r);
if (ldist < rdist) {
i = li, j = lj, d = ldist;
} else {
i = ri, j = rj, d = rdist;
}
inplace_merge(pts.begin() + l, pts.begin() + mid, pts.begin() + r, cmp_y);
buf.clear();
for (int a = l; a < r; a++) {
if (abs(x - pts[a].first.x) >= d) continue;
for (int b = buf.size() - 1; b >= 0; b--) {
if (pts[a].first.y - buf[b].first.y >= d) break;
ld cur = dist(pts[a].first, buf[b].first);
if (cur < d) i = pts[a].second, j = buf[b].second, d = cur;
}
buf.push_back(pts[a]);
}
}
return tuple{i, j, d};
};
return recurse(0, n);
}
Line abc_to_line(ld a, ld b, ld c) {
assert(!sgn(a) || !sgn(b));
if (a == 0) return Line(Point(0, -c / b), Point(1, -c / b));
if (b == 0) return Line(Point(-c / a, 0), Point(-c / a, 1));
Point s(0, -c / b), e(1, (-c - a) / b), diff = e - s;
return Line(s, s + diff / dist(diff));
}
tuple<ld, ld, ld> line_to_abc(const Line &l) {
Point diff = l.e - l.s;
return {-diff.y, diff.x, -(diff ^ l.s)};
}
// Find polygon cut to the left of l
vector<Point> convex_cut(const vector<Point> &p, const Line &l) {
int n = p.size();
vector<Point> cut;
for (int i = 0; i < n; i++) {
auto a = p[i], b = p[(i + 1) % n];
if (sgn((l.e - l.s) ^ (a - l.s)) >= 0)
cut.push_back(a);
if (sgn((l.e - l.s) ^ (a - l.s)) * sgn((l.e - l.s) ^ (b - l.s)) == -1)
cut.push_back(intersect(Line(a, b), l));
}
return cut;
}
// Sort by angle in range [0, 2pi)
template <class RandomIt>
void polar_sort(RandomIt first, RandomIt last, Point origin = Point(0, 0)) {
auto get_quad = [&](const Point& p) {
Point diff = p - origin;
if (diff.x > 0 && diff.y >= 0) return 1;
if (diff.x <= 0 && diff.y > 0) return 2;
if (diff.x < 0 && diff.y <= 0) return 3;
return 4;
};
auto polar_cmp = [&](const Point& p1, const Point& p2) {
int q1 = get_quad(p1), q2 = get_quad(p2);
if (q1 != q2) return q1 < q2;
return ((p1 - origin) ^ (p2 - origin)) > 0;
};
sort(first, last, polar_cmp);
}
bool polar_cmp(const Point &p1, const Point &p2) {
Point o{0, 0};
auto quad = [&](const Point &p) {
Point a = p - o;
return (a.y > 0 || (a.y == 0 && a.x > 0)) ? 1 : 2;
};
int q1 = quad(p1), q2 = quad(p2);
if (q1 != q2) return q1 < q2;
return ((p1 - o) ^ (p2 - o)) > 0;
};
minimum circle covering
constexpr ld eps = 1e-9;
struct Point {
ld x, y;
Point(ll xx = 0, ll yy = 0) : x(xx), y(yy) {}
};
auto dist(const Point& a, const Point& b) {
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
int sgn(ld x) { return (abs(x) <= eps) ? 0 : (x < 0 ? -1 : 1); }
Point get_o(Point a, Point b, Point c) {
auto a1 = 2 * (b.x - a.x), b1 = 2 * (b.y - a.y);
auto c1 = b.x * b.x - a.x * a.x + b.y * b.y - a.y * a.y;
auto a2 = 2 * (c.x - a.x), b2 = 2 * (c.y - a.y);
auto c2 = c.x * c.x - a.x * a.x + c.y * c.y - a.y * a.y;
Point res;
if (!sgn(a1)) {
res.y = c1 / b1;
res.x = (c2 - res.y * b2) / a2;
} else if (!sgn(b1)) {
res.x = c1 / a1;
res.y = (c2 - res.x * a2) / b2;
} else {
res.x = (c2 * b1 - c1 * b2) / (a2 * b1 - a1 * b2);
res.y = (c2 * a1 - c1 * a2) / (b2 * a1 - b1 * a2);
}
return res;
}
for (int i = start; i < n; i++) {
if (dist(o, p[i]) <= r + eps) {
cost[start][i] = r;
continue;
}
links.push_back({start, i - 1});
o.x = (p[i].x + p[start].x) / 2;
o.y = (p[i].y + p[start].y) / 2;
r = dist(p[i], p[start]) / 2;
for (int j = start + 1; j < i; j++) {
if (dist(o, p[j]) <= r + eps) continue;
o.x = (p[i].x + p[j].x) / 2;
o.y = (p[i].y + p[j].y) / 2;
r = dist(p[i], p[j]) / 2;
for (int k = start; k < j; k++) {
if (dist(o, p[k]) <= r + eps) continue;
o = get_o(p[i], p[j], p[k]);
r = dist(o, p[i]);
}
}
cost[start][i] = r;
}