ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【题解】Mogohu-Rea Idol [CF87E]

2020-06-01 21:01:29  阅读:264  来源: 互联网

标签:Rea return 题解 while dcmp vec CF87E cp Cro


【题解】Mogohu-Rea Idol [CF87E]

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

【题目描述】

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

【分析】

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

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

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

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

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

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

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

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

其实可以把两部分求凸包的过程都换掉:前面枚举找最小点、多加一个特判处理重边,就变成了 \(O(n+m\log 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");
}

标签:Rea,return,题解,while,dcmp,vec,CF87E,cp,Cro
来源: https://www.cnblogs.com/Xing-Ling/p/13027432.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有