题意:给了n条直线,每个直线方程用 y=ax+b y = a x + b 的形式给出。
现有m个询问,每次给出一条直线
y=cx+d
y
=
c
x
+
d
的形式,求该直线与前
n
n
条直线交点中X坐标在x轴正半轴中最大的那个。
思路:
简单计算可知 两条直线交点的坐标 为 (a,b) ( a , b ) 和 (c,d) ( c , d ) 两点斜率的相反数。所以很自然的想到可以用凸包解决这个问题。
关键问题:点在凸包内如何处理。
#include<bits/stdc++.h>
using namespace std;
struct point {
int x, y, id;
void read(int i) {
scanf("%d%d", &x, &y);
x = -x;
id = i;
}
point (int x = 0, int y = 0) :x(x), y(y) {}
point operator + (const point &rhs) const {
return point(x + rhs.x, y + rhs.y);
}
point operator - (const point &rhs) const {
return point(x - rhs.x, y - rhs.y);
}
bool operator < (const point &rhs) const {
if (x == rhs.x) return y < rhs.y;
return x < rhs.x;
}
};
long long cross(point a, point b) {
return 1ll * a.x * b.y - 1ll * a.y * b.x;
}
const int N = 1e5 + 20;
point p[N], ch[N];
double ans[N];
int n, m, q;
double k(point t) {
return 1.0 * t.y / t.x;
}
void solve() {
m = 0;
for (int i = 0; i < n + q; i++) {
if (p[i].id) {
int l = 0, r = m - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (cross(p[i] - ch[mid], p[i] - ch[mid + 1]) <= 0) r = mid;
else l = mid + 1;
}
if (l < m) ans[p[i].id] = max(k(p[i] - ch[l]), ans[p[i].id]);
}
else {
while (m > 1 && cross(ch[m - 2] - ch[m - 1], ch[m - 2] - p[i]) <= 0) m--;
ch[m++] = p[i];
}
}
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) p[i].read(0);
scanf("%d", &q);
for (int i = 0; i < q; i++) p[i + n].read(i + 1);
sort(p, p + n + q);
solve();
reverse(p, p + n + q);
solve();
for (int i = 1; i <= q; i++) if (ans[i] < 1e-9) puts("No cross");
else printf("%.9f\n", ans[i]);
}