zoukankan      html  css  js  c++  java
  • 2018暑假牛客多校二 C(凸包)

    题目描述:

        有一个无线大的平面,平面上有n条斜率不为零的直线。 有m次询问,每次询问从y轴上的一个点出发往x轴正方向沿一条直线走,最后一个与这n条直线相交的点的 横坐标。 n,m<=50000

    题目分析:

        根据题意我们可以,如果一条直线为 y=ax+b,另一条直线为 y=cx+d,则我们容易得出他们的交点的横坐标为 。

    因此我们可以将这个横坐标看作是两个点(a,b),(c,d)之间的斜率的相反数。

        因此我们就可以将题目转化成:在平面内又n个点pi,每次给一个点p,问这个点到平面内所有点的斜率最小值。

        而因为最小值相对来说没这么好处理,因此我们则可以将所有点的横坐标取反,则这个题就转化为求斜率的最大值。

        对于这个问题,我们就可以通过凸包进行维护。

        具体的做法是:我们先根据题目给出的n个直线(将他们看成一个个点对),做一个凸包。因为做出来的凸包上的每一个点是存在一定的单调性的,因此我们可以在凸包上二分查找出跟询问的点p斜率最大的点。(具体的二分操作是如果发现当前选到的凸包上的两点p1,p2与询问的点p的叉积,则证明 pp1的斜率小于pp2,则向左区间二分,以此类推)

        当找到斜率最大的点后,不断更新答案即可。

    代码:

    #include <bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    const double eps=1e-8;
    int sgn(double x){
        if(fabs(x)<eps) return 0;
        if(x<eps) return -1;
        else return 1;
    }
    struct Point{
        double x,y;
        int id;
        Point(double _x=0, double _y=0,int _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 getk(Point a){
        return a.y/a.x;
    }
    double cross(Point a,Point b,Point c){
        return (b-a)^(c-a);
    }
    Point p[maxn],q[maxn];
    double ans[maxn];
    void Graham(int n){
        int num=0;
        for(int i=0;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=0;i<n;i++){
            scanf("%lf%lf",&p[i].x,&p[i].y),p[i].x=-p[i].x;
        }
        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,p[i+n].x=-p[i+n].x;
        }
        sort(p,p+n+m);
        Graham(n+m);
        reverse(p,p+n+m);
        Graham(n+m);
        for(int i=1;i<=m;i++){
            if(sgn(ans[i])==0) puts("No cross");
            else printf("%.8f
    ",ans[i]);
        }
    }
    
  • 相关阅读:
    Day13
    Day12
    Day11
    Day10
    Day9
    Day8
    Day7
    mac上使用gitlab拉项目报错Permissions 0644 for ...
    vue-cli3使用svg
    js合并多个array
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007260.html
Copyright © 2011-2022 走看看