zoukankan      html  css  js  c++  java
  • 【题解】Mogohu-Rea Idol [CF87E]

    【题解】Mogohu-Rea Idol [CF87E]

    传送门:( ext{Mogohu-Rea Idol}) ( ext{[CF87E]})

    【题目描述】

    按逆时针顺序给出三个凸包点集 (A,B,C),每次查询给出点 (q),问是否存在点 (ain A,bin B,cin C) 满足 (q)(Delta abc) 的重心。

    【分析】

    【学习笔记】计算几何全家桶

    目前我所知的第三道闵可夫斯基和的题(貌似是个冷门老题)

    考虑三角形重心 (Q) 的基本性质:(vec{OA}+vec{OB}+vec{OC}=3vec{OQ})

    然后就是个板子题了...

    对三个凸包求个和,得到 (P={a+b+c|ain A,bin B,cin C}),然后直接判断点 (q*3) 是否在 (P) 以内即可。

    注意题目给出的虽然是严格凸包,但还是要自己写个算法跑一下,目的是将坐标最小的放在第一个位置,否则后面对凸包求和时会出问题(也可以直接枚举找最小点作为凸包起点)。

    然后就是做完闵可夫斯基和后要再对其求一下凸包,目的是去掉平行边(或者说重边。在 (P) 上表现为三点共线)。

    时间复杂度:(O((n+m)log n))

    其实可以把两部分求凸包的过程都换掉:前面枚举找最小点、多加一个特判处理重边,就变成了 (O(n+mlog n)),但意义不大。

    【Code】

    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #define LD double
    #define LL long long
    #define Vector Point
    #define Re register int
    using namespace std;
    const int N=5e4+3;
    const LD eps=1e-8,Pi=acos(-1.0);
    inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
    inline void in(Re &x){
        int f=0;x=0;char c=getchar();
        while(c<'0'||c>'9')f|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=f?-x:x;
    }
    struct Point{
        LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
        inline void In(){Re X,Y;in(X),in(Y),x=X,y=Y;}
        inline bool operator<(const Point &O)const{return dcmp(x-O.x)?x<O.x:y<O.y;}
    };
    inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
    inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
    inline Vector operator+(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
    inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
    inline Vector operator*(Vector a,LD b){return Vector(a.x*b,a.y*b);}
    inline int pan_PL(Point p,Point a,Point b){//【判断点P是否在直线AB上】
        return !dcmp(Cro(p-a,p-b))&&dcmp(Dot(p-a,p-b))<0;
    }
    inline bool cmp1(Vector a,Vector b){return a.x==b.x?a.y<b.y:a.x<b.x;};//按坐标排序
    inline int ConvexHull(Point *P,Re n,Point *cp){//【Graham扫描法】求凸包
        sort(P+1,P+n+1,cmp1);
        Re t=0;
        for(Re i=1;i<=n;++i){//下凸包
            while(t>1&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
            cp[++t]=P[i];
        }
        Re St=t;
        for(Re i=n-1;i>=1;--i){//上凸包
            while(t>St&&dcmp(Cro(cp[t]-cp[t-1],P[i]-cp[t-1]))<=0)--t;
            cp[++t]=P[i];
        }
        return --t;//要减一
    }
    inline int PIP(Point *P,Re n,Point a){//【二分法】判断点A是否在凸多边形Poly以内
        //点按逆时针给出
        if(dcmp(Cro(a-P[1],P[2]-P[1]))>0||dcmp(Cro(P[n]-P[1],a-P[1]))>0)return 0;//在P[1_2]或P[1_n]外
        if(pan_PL(a,P[1],P[2])||pan_PL(a,P[1],P[n]))return 1;//在P[1_2]或P[1_n]上
        Re l=2,r=n-1;
        while(l<r){//二分找到一个位置pos使得P[1]_A在P[1_pos],P[1_(pos+1)]之间
            Re mid=l+r+1>>1;
            if(dcmp(Cro(a-P[1],P[mid]-P[1]))>0)r=mid-1;
            else l=mid;
        }
        return dcmp(Cro(a-P[r],P[r+1]-P[r]))<=0;
    }
    Vector V1[N*3],V2[N*3];
    inline int Mincowski(Point *P1,Re n,Point *P2,Re m,Point *P){//【闵可夫斯基和】求两个凸包{P1},{P2}的向量集合{V}={P1+P2}构成的凸包
        for(Re i=1;i<=n;++i)V1[i]=P1[i<n?i+1:1]-P1[i];
        for(Re i=1;i<=m;++i)V2[i]=P2[i<m?i+1:1]-P2[i];
        Re t=0,i=1,j=1;P[++t]=P1[1]+P2[1];
        while(i<=n&&j<=m)++t,P[t]=P[t-1]+(dcmp(Cro(V1[i],V2[j]))>0?V1[i++]:V2[j++]);
        while(i<=n)++t,P[t]=P[t-1]+V1[i++];
        while(j<=m)++t,P[t]=P[t-1]+V2[j++];
        return t;
    }
    int n,T,n1,n2,n3;Point Q,P[N*3],cp[N*3],P1[N],P2[N],P3[N];
    int main(){
    //    freopen("123.txt","r",stdin);
        in(n1);for(Re i=1;i<=n1;++i)P1[i].In();n1=ConvexHull(P1,n1,cp);for(Re i=1;i<=n1;++i)P1[i]=cp[i];
        in(n2);for(Re i=1;i<=n2;++i)P2[i].In();n2=ConvexHull(P2,n2,cp);for(Re i=1;i<=n2;++i)P2[i]=cp[i];
        in(n3);for(Re i=1;i<=n3;++i)P3[i].In();n3=ConvexHull(P3,n3,cp);for(Re i=1;i<=n3;++i)P3[i]=cp[i];
        n=Mincowski(P1,n1,P2,n2,P),n=Mincowski(P,n,P3,n3,cp),n=ConvexHull(cp,n,P),in(T);//这里对P求一次凸包或者分开求两次凸包效果都是一样的
    //    n=Mincowski(P1,n1,P2,n2,cp),n=ConvexHull(cp,n,P);
    //    n=Mincowski(P,n,P3,n3,cp),n=ConvexHull(cp,n,P),in(T);
        while(T--)Q.In(),puts(PIP(P,n,Q*3.0)?"YES":"NO");
    }
    
  • 相关阅读:
    Leetcode 538. Convert BST to Greater Tree
    Leetcode 530. Minimum Absolute Difference in BST
    Leetcode 501. Find Mode in Binary Search Tree
    Leetcode 437. Path Sum III
    Leetcode 404. Sum of Left Leaves
    Leetcode 257. Binary Tree Paths
    Leetcode 235. Lowest Common Ancestor of a Binary Search Tree
    Leetcode 226. Invert Binary Tree
    Leetcode 112. Path Sum
    Leetcode 111. Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/13027432.html
Copyright © 2011-2022 走看看