結果
問題 |
No.3154 convex polygon judge
|
ユーザー |
![]() |
提出日時 | 2025-05-20 21:36:52 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 307 ms / 2,000 ms |
コード長 | 22,547 bytes |
コンパイル時間 | 5,262 ms |
コンパイル使用メモリ | 319,568 KB |
実行使用メモリ | 22,924 KB |
最終ジャッジ日時 | 2025-05-20 21:37:02 |
合計ジャッジ時間 | 8,425 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 44 |
ソースコード
#include <bits/stdc++.h> using namespace std; #define ALL(x) (x).begin(),(x).end() #define IO ios::sync_with_stdio(false),cin.tie(nullptr); #define REP(i, n) for(ll i=0; i<(ll)(n); i++) #define FOR(i, a, b) for(ll i=(ll)(a); (a)<(b) ? i<(b) : i>(b); i+=((a)<(b) ? 1 : -1)) template<typename T> int LB(const vector<T>& v, T x) { return lower_bound(ALL(v),x)-(v).begin(); } template<typename T> int UQ(T& v) { sort(ALL(v)); v.erase(unique(ALL(v)),v.end()); return v.size(); } template<typename T> bool chmax(T &a, T b) { return a<b ? a=b, true : false; } template<typename T> bool chmin(T &a, T b) { return a>b ? a=b, true : false; } template<typename T> using rpriority_queue=priority_queue<T,vector<T>,greater<T>>; using ll=long long; const int INF=1e9+10; const ll INFL=4e18; using ld=long double; using ull=unsigned long long; using lll=__int128_t; using VI=vector<int>; using VVI=vector<VI>; using VL=vector<ll>; using VVL=vector<VL>; using PL=pair<ll,ll>; using VP=vector<PL>; using WG=vector<vector<pair<int,ll>>>; #ifdef LOCAL #include "./debug.hpp" #else #define debug(...) #define print_line #endif namespace Geometry{ using Real=long double; const Real EPS=1e-9; bool almostEqual(Real a,Real b){return abs(a-b)<EPS;} bool lessThan(Real a,Real b){return a<b&&!almostEqual(a,b);} bool greaterThan(Real a,Real b){return a>b&&!almostEqual(a,b);} bool lessThanOrEqual(Real a,Real b){return a<b||almostEqual(a,b);} bool greaterThanOrEqual(Real a,Real b){return a>b||almostEqual(a,b);} struct Point{ Real x,y; Point()=default; Point(Real x,Real y):x(x),y(y){} Point operator+(const Point&p)const{return Point(x+p.x,y+p.y);} Point operator-(const Point&p)const{return Point(x-p.x,y-p.y);} Point operator*(Real k)const{return Point(x*k,y*k);} Point operator/(Real k)const{return Point(x/k,y/k);} Real dot(const Point&p)const{return x*p.x+y*p.y;} Real cross(const Point&p)const{return x*p.y-y*p.x;} Real cross(const Point&p1,const Point&p2)const{return(p1.x-x)*(p2.y-y)-(p1.y-y)*(p2.x-x);} Real norm()const{return x*x+y*y;} Real abs()const{return sqrt(norm());} Real arg()const{return atan2(y,x);} bool operator==(const Point&p)const{return almostEqual(x,p.x)&&almostEqual(y,p.y);} friend istream&operator>>(istream&is,Point&p){return is>>p.x>>p.y;} }; struct Line{ Point a,b; Line()=default; Line(const Point&_a,const Point&_b):a(_a),b(_b){} //Ax+By=C Line(const Real&A,const Real&B,const Real&C){ if(almostEqual(A,0)){ assert(!almostEqual(B,0)); a=Point(0,C/B); b=Point(1,C/B); }else if(almostEqual(B,0)){ a=Point(C/A,0); b=Point(C/A,1); }else if(almostEqual(C,0)){ a=Point(0,C/B); b=Point(1,(C-A)/B); }else{ a=Point(0,C/B); b=Point(C/A,0); } } bool operator==(const Line&l)const{return a==l.a&&b==l.b;} friend istream&operator>>(istream&is,Line&l){return is>>l.a>>l.b;} }; struct Segment:Line{ Segment()=default; using Line::Line; }; struct Circle{ Point center; Real r; Circle()=default; Circle(Real x,Real y,Real r):center(x,y),r(r){} Circle(Point _center,Real r):center(_center),r(r){} bool operator==(const Circle&C)const{return center==C.center&&r==C.r;} friend istream&operator>>(istream&is,Circle&C){return is>>C.center>>C.r;} }; //----------------------------------------------------------- enum Orientation{ COUNTER_CLOCKWISE, CLOCKWISE, ONLINE_BACK, ONLINE_FRONT, ON_SEGMENT }; Orientation ccw(const Point&p0,const Point&p1,const Point&p2){ Point a=p1-p0; Point b=p2-p0; Real cross_product=a.cross(b); if(greaterThan(cross_product,0))return COUNTER_CLOCKWISE; if(lessThan(cross_product,0))return CLOCKWISE; if(lessThan(a.dot(b),0))return ONLINE_BACK; if(lessThan(a.norm(),b.norm()))return ONLINE_FRONT; return ON_SEGMENT; } string orientationToString(Orientation o){ switch(o){ case COUNTER_CLOCKWISE: return"COUNTER_CLOCKWISE"; case CLOCKWISE: return"CLOCKWISE"; case ONLINE_BACK: return"ONLINE_BACK"; case ONLINE_FRONT: return"ONLINE_FRONT"; case ON_SEGMENT: return"ON_SEGMENT"; default: return"UNKNOWN"; } } Point projection(const Point&p1,const Point&p2,const Point&p){ Point base=p2-p1; Real r=(p-p1).dot(base)/base.norm(); return p1+base*r; } Point projection(const Line&l,const Point&p){ Point base=l.b-l.a; Real r=(p-l.a).dot(base)/base.norm(); return l.a+base*r; } Point reflection(const Point&p1,const Point&p2,const Point&p){ Point proj=projection(p1,p2,p); return proj*2-p; } Point reflection(const Line&l,const Point&p){ Point proj=projection(l,p); return proj*2-p; } //----------------------------------------------------------- bool isParallel(const Line&l1,const Line&l2){return almostEqual((l1.b-l1.a).cross(l2.b-l2.a),0);} bool isOrthogonal(const Line&l1,const Line&l2){return almostEqual((l1.b-l1.a).dot(l2.b-l2.a),0);} bool isParallel(const Segment&l1,const Segment&l2){return almostEqual((l1.b-l1.a).cross(l2.b-l2.a),0);} bool isOrthogonal(const Segment&l1,const Segment&l2){return almostEqual((l1.b-l1.a).dot(l2.b-l2.a),0);} bool isParallel(const Line&l1,const Segment&l2){return almostEqual((l1.b-l1.a).cross(l2.b-l2.a),0);} bool isOrthogonal(const Line&l1,const Segment&l2){return almostEqual((l1.b-l1.a).dot(l2.b-l2.a),0);} bool isParallel(const Segment&l1,const Line&l2){return almostEqual((l1.b-l1.a).cross(l2.b-l2.a),0);} bool isOrthogonal(const Segment&l1,const Line&l2){return almostEqual((l1.b-l1.a).dot(l2.b-l2.a),0);} bool isPointOnLine(const Point&p,const Line&l){return almostEqual((l.b-l.a).cross(p-l.a),0.0);} bool isPointOnSegment(const Point&p,const Segment&s){ return lessThanOrEqual(min(s.a.x,s.b.x),p.x)&& lessThanOrEqual(p.x,max(s.a.x,s.b.x))&& lessThanOrEqual(min(s.a.y,s.b.y),p.y)&& lessThanOrEqual(p.y,max(s.a.y,s.b.y))&& almostEqual((s.b-s.a).cross(p-s.a),0.0); } bool isIntersecting(const Segment&s1,const Segment&s2){ Point p0p1=s1.b-s1.a; Point p0p2=s2.a-s1.a; Point p0p3=s2.b-s1.a; Point p2p3=s2.b-s2.a; Point p2p0=s1.a-s2.a; Point p2p1=s1.b-s2.a; Real d1=p0p1.cross(p0p2); Real d2=p0p1.cross(p0p3); Real d3=p2p3.cross(p2p0); Real d4=p2p3.cross(p2p1); if(lessThan(d1*d2,0)&&lessThan(d3*d4,0))return true; if(almostEqual(d1,0.0)&&isPointOnSegment(s2.a,s1))return true; if(almostEqual(d2,0.0)&&isPointOnSegment(s2.b,s1))return true; if(almostEqual(d3,0.0)&&isPointOnSegment(s1.a,s2))return true; if(almostEqual(d4,0.0)&&isPointOnSegment(s1.b,s2))return true; return false; } Point getIntersection(const Segment&s1,const Segment&s2){ assert(isIntersecting(s1,s2)); auto cross=[](Point p,Point q){return p.x*q.y-p.y*q.x;}; Point base=s2.b-s2.a; Real d1=abs(cross(base,s1.a-s2.a)); Real d2=abs(cross(base,s1.b-s2.a)); Real t=d1/(d1+d2); return s1.a+(s1.b-s1.a)*t; } Real distancePointToSegment(const Point&p,const Segment&s){ Point proj=projection(s.a,s.b,p); if(isPointOnSegment(proj,s)){ return(p-proj).abs(); }else{ return min((p-s.a).abs(),(p-s.b).abs()); } } Real distanceSegmentToSegment(const Segment&s1,const Segment&s2){ if(isIntersecting(s1,s2))return 0.0; return min( {distancePointToSegment(s1.a,s2),distancePointToSegment(s1.b,s2), distancePointToSegment(s2.a,s1),distancePointToSegment(s2.b,s1)}); } //----------------------------------------------------------- Real getPolygonArea(const vector<Point>&points){ int n=points.size(); Real area=0.0; for(int i=0;i<n;++i){ int j=(i+1)%n; area+=points[i].x*points[j].y; area-=points[i].y*points[j].x; } return abs(area)/2.0; } bool isConvex(const vector<Point>&points){ int n=points.size(); bool has_positive=false,has_negative=false; for(int i=0;i<n;++i){ int j=(i+1)%n; int k=(i+2)%n; Point a=points[j]-points[i]; Point b=points[k]-points[j]; Real cross_product=a.cross(b); if(greaterThan(cross_product,0))has_positive=true; if(lessThan(cross_product,0))has_negative=true; } return!(has_positive&&has_negative); } bool isPointOnPolygon(const vector<Point>&polygon,const Point&p){ int n=polygon.size(); for(int i=0;i<n;++i){ Point a=polygon[i]; Point b=polygon[(i+1)%n]; Segment s(a,b); if(isPointOnSegment(p,s))return true; } return false; } bool isPointInsidePolygon(const vector<Point>&polygon,const Point&p){ int n=polygon.size(); bool inPolygon=false; for(int i=0;i<n;++i){ Point a=polygon[i]; Point b=polygon[(i+1)%n]; if(greaterThan(a.y,b.y))swap(a,b); if(lessThanOrEqual(a.y,p.y)&&lessThan(p.y,b.y)&&greaterThan((b-a).cross(p-a),0))inPolygon=!inPolygon; } return inPolygon; } //----------------------------------------------------------- vector<Point>convexHull(vector<Point>&points,bool include_collinear=false){ int n=points.size(); if(n<=1)return points; sort(points.begin(),points.end(),[](const Point&l,const Point&r)->bool{ if(almostEqual(l.y,r.y))return lessThan(l.x,r.x); return lessThan(l.y,r.y); }); if(n==2)return points; vector<Point>upper={points[0],points[1]},lower={points[0],points[1]}; for(int i=2;i<n;++i){ while((int)upper.size()>=2&&ccw(upper.end()[-2],upper.end()[-1],points[i])!=CLOCKWISE){ if(ccw(upper.end()[-2],upper.end()[-1],points[i])==ONLINE_FRONT&&include_collinear)break; upper.pop_back(); } upper.push_back(points[i]); while((int)lower.size()>=2&&ccw(lower.end()[-2],lower.end()[-1],points[i])!=COUNTER_CLOCKWISE){ if(ccw(lower.end()[-2],lower.end()[-1],points[i])==ONLINE_FRONT&&include_collinear)break; lower.pop_back(); } lower.push_back(points[i]); } reverse(upper.begin(),upper.end()); upper.pop_back(); lower.pop_back(); lower.insert(lower.end(),upper.begin(),upper.end()); return lower; } Real convexHullDiameter(const vector<Point>&hull){ int n=hull.size(); if(n==1)return 0; int k=1; Real max_dist=0; for(int i=0;i<n;++i){ while(true){ int j=(k+1)%n; Point dist1=hull[i]-hull[j],dist2=hull[i]-hull[k]; max_dist=max(max_dist,dist1.abs()); max_dist=max(max_dist,dist2.abs()); if(dist1.abs()>dist2.abs()){ k=j; }else{ break; } } Point dist=hull[i]-hull[k]; max_dist=max(max_dist,dist.abs()); } return max_dist; } vector<Point>cutPolygon(const vector<Point>&g,const Line&l){ auto isLeft=[](const Point&p1,const Point&p2,const Point&p)->bool{return(p2-p1).cross(p-p1)>0;}; vector<Point>newPolygon; int n=g.size(); for(int i=0;i<n;++i){ const Point&cur=g[i]; const Point&next=g[(i+1)%n]; if(isLeft(l.a,l.b,cur))newPolygon.push_back(cur); if((isLeft(l.a,l.b,cur)&&!isLeft(l.a,l.b,next))||(!isLeft(l.a,l.b,cur)&&isLeft(l.a,l.b,next))){ Real A1=(next-cur).cross(l.a-cur); Real A2=(next-cur).cross(l.b-cur); Point intersection=l.a+(l.b-l.a)*(A1/(A1-A2)); newPolygon.push_back(intersection); } } return newPolygon; } //----------------------------------------------------------- Real closestPair(vector<Point>&points,int l,int r){ if(r-l<=1)return numeric_limits<Real>::max(); int mid=(l+r)>>1; Real x=points[mid].x; Real d=min(closestPair(points,l,mid),closestPair(points,mid,r)); auto iti=points.begin(),itl=iti+l,itm=iti+mid,itr=iti+r; inplace_merge(itl,itm,itr,[](const Point&lhs,const Point&rhs)->bool{ return lessThan(lhs.y,rhs.y); }); vector<Point>nearLine; for(int i=l;i<r;++i){ if(greaterThanOrEqual(fabs(points[i].x-x),d))continue; int sz=nearLine.size(); for(int j=sz-1;j>=0;--j){ Point dv=points[i]-nearLine[j]; if(dv.y>=d)break; d=min(d,dv.abs()); } nearLine.push_back(points[i]); } return d; } //----------------------------------------------------------- int countIntersections(vector<Segment>segments){ struct Event{ Real x; int type;//0:horizontal start,1:vertical,2:horizontal end Real y1,y2; Event(Real x,int type,Real y1,Real y2):x(x),type(type),y1(y1),y2(y2){} bool operator<(const Event&other)const{ if(x==other.x)return type<other.type; return x<other.x; } }; vector<Event>events; sort(segments.begin(),segments.end(),[](const Segment&lhs,const Segment&rhs)->bool{ return lessThan(min(lhs.a.x,lhs.b.x),min(rhs.a.x,rhs.b.x)); }); for(const auto&seg:segments){ if(seg.a.y==seg.b.y){ //Horizontal segment Real y=seg.a.y; Real x1=min(seg.a.x,seg.b.x); Real x2=max(seg.a.x,seg.b.x); events.emplace_back(x1,0,y,y); events.emplace_back(x2,2,y,y); }else{ //Vertical segment Real x=seg.a.x; Real y1=min(seg.a.y,seg.b.y); Real y2=max(seg.a.y,seg.b.y); events.emplace_back(x,1,y1,y2); } } sort(events.begin(),events.end()); set<Real>activeSegments; int intersectionCount=0; for(const auto&event:events){ if(event.type==0){ //Add horizontal segment to active set activeSegments.insert(event.y1); }else if(event.type==2){ //Remove horizontal segment from active set activeSegments.erase(event.y1); }else if(event.type==1){ //Count intersections with vertical segment auto lower=activeSegments.lower_bound(event.y1); auto upper=activeSegments.upper_bound(event.y2); intersectionCount+=distance(lower,upper); } } return intersectionCount; } //----------------------------------------------------------- int countCirclesIntersection(const Circle&c1,const Circle&c2){ Real d=sqrt((c1.center.x-c2.center.x)*(c1.center.x-c2.center.x)+ (c1.center.y-c2.center.y)*(c1.center.y-c2.center.y)); Real r1=c1.r,r2=c2.r; if(greaterThan(d,r1+r2)){ return 4; }else if(almostEqual(d,r1+r2)){ return 3; }else if(greaterThan(d,fabs(r1-r2))){ return 2; }else if(almostEqual(d,fabs(r1-r2))){ return 1; }else{ return 0; } } Circle getInCircle(const Point&A,const Point&B,const Point&C){ Real a=(B-C).abs(); Real b=(A-C).abs(); Real c=(A-B).abs(); Real s=(a+b+c)/2; Real area=sqrt(s*(s-a)*(s-b)*(s-c)); Real r=area/s; Real cx=(a*A.x+b*B.x+c*C.x)/(a+b+c); Real cy=(a*A.y+b*B.y+c*C.y)/(a+b+c); return Circle{Point(cx,cy),r}; } Circle getCircumCircle(const Point&A,const Point&B,const Point&C){ Real D=2*(A.x*(B.y-C.y)+B.x*(C.y-A.y)+C.x*(A.y-B.y)); Real Ux=((A.x*A.x+A.y*A.y)*(B.y-C.y)+(B.x*B.x+B.y*B.y)*(C.y-A.y)+(C.x*C.x+C.y*C.y)*(A.y-B.y))/D; Real Uy=((A.x*A.x+A.y*A.y)*(C.x-B.x)+(B.x*B.x+B.y*B.y)*(A.x-C.x)+(C.x*C.x+C.y*C.y)*(B.x-A.x))/D; Point center(Ux,Uy); Real radius=(center-A).abs(); return Circle{center,radius}; } vector<Point>getCircleLineIntersection(const Circle&c,Point p1,Point p2){ Real cx=c.center.x,cy=c.center.y,r=c.r; Real dx=p2.x-p1.x; Real dy=p2.y-p1.y; Real a=dx*dx+dy*dy; Real b=2*(dx*(p1.x-cx)+dy*(p1.y-cy)); Real c_const=(p1.x-cx)*(p1.x-cx)+(p1.y-cy)*(p1.y-cy)-r*r; Real discriminant=b*b-4*a*c_const; vector<Point>intersections; if(almostEqual(discriminant,0)){ Real t=-b/(2*a); Real ix=p1.x+t*dx; Real iy=p1.y+t*dy; intersections.emplace_back(ix,iy); intersections.emplace_back(ix,iy); }else if(discriminant>0){ Real sqrt_discriminant=sqrt(discriminant); Real t1=(-b+sqrt_discriminant)/(2*a); Real t2=(-b-sqrt_discriminant)/(2*a); Real ix1=p1.x+t1*dx; Real iy1=p1.y+t1*dy; Real ix2=p1.x+t2*dx; Real iy2=p1.y+t2*dy; intersections.emplace_back(ix1,iy1); intersections.emplace_back(ix2,iy2); } if(almostEqual(intersections[0].x,intersections[1].x)){ if(greaterThan(intersections[0].y,intersections[1].y))swap(intersections[0],intersections[1]); }else if(greaterThan(intersections[0].x,intersections[1].x)){ swap(intersections[0],intersections[1]); } return intersections; } vector<Point>getCirclesIntersect(const Circle&c1,const Circle&c2){ Real x1=c1.center.x,y1=c1.center.y,r1=c1.r; Real x2=c2.center.x,y2=c2.center.y,r2=c2.r; Real d=sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if(d>r1+r2||d<abs(r1-r2))return{};//No intersection Real a=(r1*r1-r2*r2+d*d)/(2*d); Real h=sqrt(r1*r1-a*a); Real x0=x1+a*(x2-x1)/d; Real y0=y1+a*(y2-y1)/d; Real rx=-(y2-y1)*(h/d); Real ry=(x2-x1)*(h/d); Point p1(x0+rx,y0+ry); Point p2(x0-rx,y0-ry); vector<Point>intersections; intersections.push_back(p1); intersections.push_back(p2); if(almostEqual(intersections[0].x,intersections[1].x)){ if(greaterThan(intersections[0].y,intersections[1].y))swap(intersections[0],intersections[1]); }else if(greaterThan(intersections[0].x,intersections[1].x)){ swap(intersections[0],intersections[1]); } return intersections; } vector<Point>getTangentLinesFromPoint(const Circle&c,const Point&p){ Real cx=c.center.x,cy=c.center.y,r=c.r; Real px=p.x,py=p.y; Real dx=px-cx; Real dy=py-cy; Real d=(p-c.center).abs(); if(lessThan(d,r)){ return{};//No tangents if the point is inside the circle }else if(almostEqual(d,r)){ return{p}; } Real a=r*r/d; Real h=sqrt(r*r-a*a); Real cx1=cx+a*dx/d; Real cy1=cy+a*dy/d; vector<Point>tangents; tangents.emplace_back(cx1+h*dy/d,cy1-h*dx/d); tangents.emplace_back(cx1-h*dy/d,cy1+h*dx/d); if(almostEqual(tangents[0].x,tangents[1].x)){ if(greaterThan(tangents[0].y,tangents[1].y))swap(tangents[0],tangents[1]); }else if(greaterThan(tangents[0].x,tangents[1].x)){ swap(tangents[0],tangents[1]); } return tangents; } vector<Segment>getCommonTangentsLine(const Circle&c1,const Circle&c2){ Real x1=c1.center.x,y1=c1.center.y,r1=c1.r; Real x2=c2.center.x,y2=c2.center.y,r2=c2.r; Real dx=x2-x1; Real dy=y2-y1; Real d=sqrt(dx*dx+dy*dy); vector<Segment>tangents; //Coincident circles(infinite tangents) if(almostEqual(d,0)&&almostEqual(r1,r2))return tangents; //External tangents if(greaterThanOrEqual(d,r1+r2)){ Real a=atan2(dy,dx); for(int sign:{-1,1}){ Real theta=acos((r1+r2)/d); Real cx1=x1+r1*cos(a+sign*theta); Real cy1=y1+r1*sin(a+sign*theta); Real cx2=x2+r2*cos(a+sign*theta); Real cy2=y2+r2*sin(a+sign*theta); tangents.emplace_back(Segment{Point(cx1,cy1),Point(cx2,cy2)}); if(almostEqual(d,r1+r2))break; } } //Internal tangents if(greaterThanOrEqual(d,fabs(r1-r2))){ Real a=atan2(dy,dx); for(int sign:{-1,1}){ Real theta=acos((r1-r2)/d); Real cx1=x1+r1*cos(a+sign*theta); Real cy1=y1+r1*sin(a+sign*theta); Real cx2=x2-r2*cos(a+sign*theta); Real cy2=y2-r2*sin(a+sign*theta); tangents.emplace_back(Segment{Point(cx1,cy1),Point(cx2,cy2)}); if(almostEqual(d,fabs(r1-r2))) break; } } sort(tangents.begin(),tangents.end(),[&](const Segment&s1,const Segment&s2){ if(almostEqual(s1.a.x,s2.a.x)){ return lessThan(s1.a.y,s2.a.y); }else{ return lessThan(s1.a.x,s2.a.x); } }); return tangents; } } //---------------------------------------------------------- int main() { ll N; cin>>N; vector<Geometry::Point> xy(N); REP(i,N) cin>>xy[i]; cout<<(Geometry::convexHull(xy).size()==N?"Yes":"No")<<endl; }