牛客网暑期ACM多校训练营(第二场)C: message(凸包+二分)

链接:https://www.nowcoder.com/acm/contest/140/C

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 262144K,其他语言524288K
Special Judge, 64bit IO Format: %lld
题目描述
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.

输入描述:
The first line of input contains an integer n. (n<=50000)
For the next n lines, the i-th line contains 2 integers A[i], B[i], describing the i-th line. (-1e9<=A[i],B[i]<=1e9)
All numbers A[i] are different.
The next line contains an integer m. (m<=50000)
For the next m lines, the i-th line contains 2 integers C[i],D[i], describing the i-th pair.(-2e9<=C[i],D[i]<=2e9)
Each C[j] is different from any of the numbers A[i].
Each D[j] is different from any of the numbers B[i].
输出描述:
Print m lines. The i-th line contains a real number with at least 6 digits after the decimal point, denoting the latest time White Cloud can receive a message. Your answer must be correct within an absolute error of 1e-6.
If White Cloud can’t receive any message during White Rabbit’s trip,print a string “No cross”.
示例1
输入
2
0 -1
1 2
3
-1 4
2 -2
2 5
输出
5.000000000000000
4.000000000000000
No cross


题解:一条直线的表达式为 a x + b ,一次询问线的表达式为 c x + d ,则这两条线的交点是 x = b d a c
如果我们把它们看做两个点 ( a , b ) ( c , d ) ,则直线交点就是现在这两个点的斜率的相反数。
问题就转化成了:平面上有若干个点,每次给一个点,问这个点到平面上所有点的斜率最小值。
这个就可以用凸包进行维护了。
因为要保证斜率最小,所以凸包里维护的并不是最外面的点,而是里面的点。
更新答案的时候,利用二分在凸包里查找。

#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
typedef long long ll;
struct Point
{
    ll x,y,id;
    Point(ll x=0,ll y=0):x(x),y(y){}
    void show(){cout<<"("<<x<<","<<y<<")"<<endl;}
}p[MAX],ch[MAX];
Point operator-(Point A,Point B){return (Point){A.x-B.x,A.y-B.y};}        //向量A-B
ll cross(Point A,Point B){return A.x*B.y-A.y*B.x;}               //向量A B的叉积
double ans[MAX];
double f(Point A){return -1.0*A.y/A.x;}
int cmp(const Point& x,const Point& y)
{
    if(x.x==y.x)return x.y<y.y;
    return x.x<y.x;
}
int Tu(Point *p,int n,Point *ch)  //求凸包
{
    sort(p,p+n,cmp);
    int m=0;
    for(int i=0;i<n;i++)
    {
        if(p[i].id)
        {
            int l=0,r=m-1;
            while(r>=l)
            {
                int mid=(l+r)/2;
                if(cross(ch[mid]-p[i],ch[mid+1]-p[i])>0)r=mid-1;
                else l=mid+1;
            }
            for(int j=l-4;j<=r+4;j++)if(0<=j&&j<m)ans[p[i].id]=max(ans[p[i].id],f(p[i]-ch[j]));
            continue;
        }
        while(m>1&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])>0)m--;
        ch[m++]=p[i];
    }
    m=0;
    for(int i=n-1;i>=0;i--)
    {
        if(p[i].id)
        {
            int l=0,r=m-1;
            while(r>=l)
            {
                int mid=(l+r)/2;
                if(cross(ch[mid]-p[i],ch[mid+1]-p[i])>0)r=mid-1;
                else l=mid+1;
            }
            for(int j=l-4;j<=r+4;j++)if(0<=j&&j<m)ans[p[i].id]=max(ans[p[i].id],f(p[i]-ch[j]));
            continue;
        }
        while(m>1&&cross(ch[m-1]-ch[m-2],p[i]-ch[m-2])>0)m--;
        ch[m++]=p[i];
    }
    if(n>1)m--;
    return m;
}
int main()
{
    int n;cin>>n;
    for(int i=0;i<n;i++)scanf("%lld%lld",&p[i].x,&p[i].y),p[i].id=0;
    int m;cin>>m;
    for(int i=n;i<n+m;i++)scanf("%lld%lld",&p[i].x,&p[i].y),p[i].id=i-n+1;
    Tu(p,n+m,ch);
    for(int i=1;i<=m;i++)
    {
        if(ans[i]==0)puts("No cross");
        else printf("%.15lf\n",ans[i]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Mitsuha_/article/details/81158520