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左边的点,将这些点构成凸包,之后在凸包上二分即可,右边同理
#include#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 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; }



