题目大意
给定平面上n个圆(圆心
1≤n≤105
题目分析
假设我们知道这个交集一定存在,那么我们现在要随便求交集上一点应该怎么做?
先根据每个圆左右两条卡住圆的垂线来确定出一个x坐标区间,使得该区间上所有点的竖直线都能和所有圆相交。如果区间不存在,那么显然无界。
然后在这个区间上我们要怎么做呢?考虑二分出这个点。先在之前求出的区间的中点作出一条竖直线,然后求出各个圆交在上面的
当然这个还是有可能存在一些其它的无解情况,毕竟我们并不能保证每次都找到矛盾的那对圆。怎么办呢?其实我们二分达到
时间复杂度
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cfloat>
#include <cmath>
using namespace std;
typedef long double db;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=100050;
const db EPS=1e-9;
inline bool equ(db x,db y){return fabs(x-y)<=EPS;}
inline int sgn(db x){return equ(x,0.0)?0:(x<0?-1:1);}
inline db sqr(db x){return x*x;}
struct P
{
db x,y;
P (db x_=0,db y_=0){x=x_,y=y_;}
};
inline P operator+(P p,P q){return P(p.x+q.x,p.y+q.y);}
inline P operator-(P p,P q){return P(p.x-q.x,p.y-q.y);}
inline P operator*(P p,db k){return P(p.x*k,p.y*k);}
inline db operator*(P p,P q){return p.x*q.x+p.y*q.y;}
inline db operator^(P p,P q){return p.x*q.y-p.y*q.x;}
inline db mod2(P p){return p*p;}
inline db mod(P p){return sqrt(mod2(p));}
inline P rotate(P p,db a){return P(p.x*cos(a)-p.y*sin(a),p.x*sin(a)+p.y*cos(a));}
inline P adjust(P p,db len){return p*(len/mod(p));}
inline db dist(P p,P q){return mod(q-p);}
struct C
{
P O;
db r;
C (){}
C (P O_,db r_=0){O=O_,r=r_;}
}cir[N];
inline void ict(C c,db x,P &p,P &q){p=adjust(P(x-c.O.x,0),c.r),x=acos(fabs(x-c.O.x)/c.r),q=c.O+rotate(p,x),p=c.O+rotate(p,-x);}
inline bool is_intersectant(C c1,C c2){return sgn(dist(c1.O,c2.O)-c1.r-c2.r)<0;}
inline void ict(C c1,C c2,P &p,P &q)
{
db d=dist(c1.O,c2.O),a=acos((sqr(c1.r)+sqr(d)-sqr(c2.r))/(2.*c1.r*d));
p=adjust(c2.O-c1.O,c1.r),q=c1.O+rotate(p,a),p=c1.O+rotate(p,-a);
}
db range[N][2];
int n;
bool judge()
{
db l=-DBL_MAX,r=DBL_MAX;
for (int i=1;i<=n;++i) l=max(cir[i].O.x-cir[i].r,l),r=min(cir[i].O.x+cir[i].r,r);
if (sgn(l-r)>=0) return 0;
for (int cas=0;cas<20;++cas)
{
db mid=(l+r)/2.;
int L=0,R=0;
for (int i=1;i<=n;++i)
{
P p,q;
ict(cir[i],mid,p,q),range[i][0]=min(p.y,q.y),range[i][1]=max(p.y,q.y);
if (!L||range[i][0]>range[L][0]) L=i;
if (!R||range[i][1]<range[R][1]) R=i;
}
if (sgn(range[L][0]-range[R][1])<0) return 1;
if (!is_intersectant(cir[L],cir[R])) return 0;
P p,q;
ict(cir[L],cir[R],p,q);
if (sgn(mid-p.x)>0) r=mid;
else l=mid;
}
return 0;
}
int main()
{
freopen("circle.in","r",stdin),freopen("circle.out","w",stdout);
n=read();
for (int i=1,x,y,r;i<=n;++i) x=read(),y=read(),r=read(),cir[i]=C(P(x,y),r);
printf(judge()?"YES\n":"NO\n");
fclose(stdin),fclose(stdout);
return 0;
}