题目大意:
n ( ≤ 50000 ) n(\le 50000) n(≤50000)条直线( y = a x + b y=ax+b y=ax+b), m ( ≤ 50000 ) m(\le 50000) m(≤50000)个询问,每次询问给出一条直线: y = c x + d y=cx+d y=cx+d,询问这条直线和 n n n条直线交点最远的点的横坐标(答案必须大于等于0)
解题思路:
-
相交的点为如下方程:
a x + b = c x + d x = b − d c − a → x = b − d − a − ( − c ) ax+b=cx+d \\ x=\frac{b-d}{c-a} \rightarrow x=\frac{b-d}{-a-(-c)} \\ ax+b=cx+dx=c−ab−d→x=−a−(−c)b−d -
问题就变成了有 n ( − a , b ) n(-a,b) n(−a,b)个点,每次询问给出一个点 ( − c , d ) (-c,d) (−c,d),求斜率最大值
-
可以分成两段来看,先看 − c -c −c左边的点,将这些点构成凸包,之后在凸包上二分即可,右边同理
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const db eps = 1e-8;
int sgn(db x) {
if (fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
int n, m;
struct Point {
db x, y;
int id;
db operator ^ (Point p) {return x * p.y - y * p.x;}
Point operator - (Point p) {return {x - p.x, y - p.y};}
bool operator < (Point p) {
if (sgn(x - p.x)) return x < p.x;
else return y < p.y;
}
} p[maxn], t[maxn];
int cross(Point p1, Point p2, Point p3) {return sgn((p2 - p1) ^ (p3 - p1));}
int cnt = 0;
db ans[maxn];
void solve() {
cnt = 0;
for (int i = 1; i <= n + m; i++) {
if (p[i].id) {
if (!cnt) continue;
int l = 1, r = cnt, m;
while (l < r) {
m = l + r >> 1;
if (cross(t[m], t[m + 1], p[i]) > 0) l = m + 1; //利用叉积来找最大的哪个斜率
//画下图可以知道,斜率最大的那个点,必然跟凸包相切,那么cross叉积就小于0,且上一个点叉积大于0
else r = m;
}
ans[p[i].id] = max(ans[p[i].id], (p[i].y - t[l].y) / (p[i].x - t[l].x));
}
else {
while (cnt > 1 && cross(t[cnt - 1], t[cnt], p[i]) <= 0) cnt--;
t[++cnt] = p[i];
}
}
}
void print() {
for (int i = n + 1; i <= n + m; i++)
if (sgn(ans[i]) <= 0) cout << "No cross" << endl;
else cout << seteps(10) << ans[i] << endl;
}
int main() {
IOS;
cin >> n;
for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y, p[i].x = -p[i].x;
cin >> m;
for (int i = n + 1; i <= n + m; i++) cin >> p[i].x >> p[i].y, p[i].id = i, p[i].x = -p[i].x;
sort (p + 1, p + n + m + 1);
solve();
reverse(p + 1, p + n + m + 1);//翻转
solve();
print();
return 0;
}