题目:给你n条直线的y=ax+by=ax+b中的aa和bb,和m次查询,每次查询给要求的直线的y=cx+dy=cx+d,中的cc和dd,要求出这条直线与n条直线交点中,x最大的值,且x大于0,如果不存在输出No cross.(n<=5e4,m<=5e4)
思路:交点x= - (b-d)/(a-c) 可以看作是两个点(a,b),(c,d)斜率的相反数。将之前输入的直线的斜率和截距看作一个点,然后就相当于找查询点与已有点的斜率的负数的最大值了。凸包维护,参考了某大佬与某大佬的两篇博客这个题终于补上了(都已经过去半个月了,菜到新高度)。
#include <bits/stdc++.h>
using namespace std;
#define inf 1e15
typedef long long ll;
const int maxn=1e5+10;
int n,m;
struct point {
double x,y;
int id;
}p[maxn],s[maxn];
double ans[maxn];
double getk(point a,point b)
{
return (b.y-a.y)/(b.x-a.x);
}
double cross(point a,point b,point c)
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
void solve()
{
int top=0;
for(int i=0;i<n+m;i++)
{
if(p[i].id==0)
{
while(top>1&&cross(s[top-1],p[i],s[top])<=0)
top--;
s[++top].x = p[i].x;
s[top].y = p[i].y;
}else
{
if(!top) continue;
int l=1,r=top;
while(r - l > 2){
int lm=(l*2+r)/3;
int rm=(l+2*r)/3;
if(getk(s[lm],p[i])<getk(s[rm],p[i]))
r=rm;
else l=lm;
}
for(int j=l;j<=r;j++)
ans[p[i].id]=max(ans[p[i].id],-getk(s[j],p[i]));
}
}
}
bool cmp(const point a,const point b)
{
return a.x<b.x;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lf%lf",&p[i].x,&p[i].y);
p[i].id=0;
}
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%lf%lf",&p[i+n].x,&p[i+n].y);
p[i+n].id=i+1;
}
for(int i=1;i<=m;i++)
ans[i]=-1.0;
sort(p,p+n+m,cmp);
solve();
for(int i=0;i<n+m;i++)
{
p[i].x=-p[i].x;
p[i].y=-p[i].y;
}
reverse(p,p+n+m);
solve();
for(int i=1;i<=m;i++)
{
if(ans[i]<0) puts("No cross");
else printf("%.15f\n",ans[i]);
}
return 0;
}