题面:
There is an infinite plane. White Cloud has n lines which are not parallel to the Oy axis. These lines in the plane are in the form y=ax+b.
White Rabbit will have a trip in the plane. It will start at time 0 and go straight along a line. specifically, White Rabbit uses 2 parameters C and D,denoting that at time x, White Rabbit is at the position(x,C*x+D).
If at some time, White Rabbit is located at one of White Cloud’s lines, White Cloud will receive a message immediately.
White Rabbit has m pairs (C[i],D[i]) for i=1…m. For each i=1…m, White Cloud wants to know if White Rabbit uses (C[i],D[i]) , when is the last time White Cloud can receive a message.
Each C[j] is different from any of the numbers A[i].
Each D[j] is different from any of the numbers B[i].
题意: 有一个无限大的平面,平面上有n条斜率不为零的直线。 有m次询问,每次询问从y轴上的一个点出发往x轴正方向沿一条直线走,最后一个与这n条直线相交的点的 横坐标。 n,m<=50000
思路: 我们可以联立两条直线
{
y
=
a
x
+
b
y
=
c
x
+
d
\begin{cases} y=ax+b\\[5ex] y=cx+d \end{cases}
⎩⎪⎪⎨⎪⎪⎧y=ax+by=cx+d解得
x
=
−
b
−
d
a
−
c
x=-\frac{b-d}{a-c}
x=−a−cb−d,然后我们可以转化成求(a,b)与(c,d)两点连线的斜率的相反数
因此我们就可以将题目转化成:在平面内又n个点pi,每次给一个点p,问这个点到平面内所有点的斜率最小值。
x
=
b
−
d
(
−
a
)
−
(
−
c
)
x=\frac{b-d}{(-a)-(-c)}
x=(−a)−(−c)b−d
我们可以将负号处理一下,将所有点的横坐标取反,变成求这个点到平面内所有点的斜率最大值。
接下来我们可以通过维护一个凸包,找到答案。
因为做出来的凸包上的每一个点是存在一定的单调性的,因此我们可以在凸包上二分查找出跟询问的点p斜率最大的点。(具体的二分操作是如果发现当前选到的凸包上的两点p1,p2与询问的点p的叉积
p
p
1
×
p
p
2
<
0
pp1\times pp2<0
pp1×pp2<0,即pp1在pp2的逆时针方向,则证明 pp1的斜率小于pp2,则向左区间二分,以此类推
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const double eps=1e-8;
int sgn(double x)
{
if(fabs(x)<=0)
return 0;
if(x<eps)
return -1;
return 1;
}
struct Point
{
double x,y;
int id;
Point(double _x=0,double _y=0,double _id=0)
{
x=_x,y=_y,id=_id;
}
Point operator -(const Point &q)
{
return Point(x-q.x,y-q.y);
}
double operator *(const Point &q)
{
return x*q.x+y*q.y;
}
double operator ^(const Point &q)
{
return x*q.y-y*q.x;
}
bool operator <(const Point &q)
{
if(sgn(x-q.x)==0)
return y<q.y;
return x<q.x;
}
};
double cross(Point a,Point b,Point c)
{
return (b-a)^(c-a);
}
Point p[N],q[N];
double ans[N];
double getk(Point a)
{
return a.y/a.x;
}
void Graham(int n)
{
int num=0;
for(int i=1;i<=n;i++)
{
if(!p[i].id)
{
while(num>1&&sgn(cross(q[num-2],q[num-1],p[i]))<=0)
num--;
q[num++]=p[i];
}
else
{
int l=0,r=num-1;
while(l<r)
{
int mid=(l+r)>>1;
if(sgn(cross(p[i],q[mid],q[mid+1]))<=0)
r=mid;
else
l=mid+1;
}
if(l<num)
{
ans[p[i].id]=max(ans[p[i].id],getk(p[i]-q[l]));
}
}
}
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
p[i].x=-p[i].x;
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%lf%lf",&p[i+n].x,&p[i+n].y);
p[i+n].x=-p[i+n].x;
p[i+n].id=i;
}
sort(p+1,p+1+n+m);
Graham(n+m);
reverse(p+1,p+1+n+m);
Graham(n+m);
for(int i=1;i<=m;i++)
{
if(sgn(ans[i])==0)
puts("No cross");
else
printf("%.8f\n",ans[i]);
}
return 0;
}