#include <bits/stdc++.h>
using namespace std;
const double eps=-1e8;
const double pi=acos(-1);
const int maxn=1005;
int cmp(double x)
{
if(abs(x)<eps)
return 0;
if(x>0)
return 1;
return -1;
}
inline double sqr(double x)
{
return x*x;
}
struct point
{
double x,y;
point(){}
point(double a,double b):x(a),y(b){}
void input()
{
scanf("%lf%lf",&x,&y);
}
friend point operator +(const point &a,const point &b)
{
return point(a.x+b.x,a.y+b.y);
}
friend point operator -(const point &a,const point &b)
{
return point(a.x-b.x,a.y-b.y);
}
friend bool operator ==(const point &a,const point &b)
{
return cmp(a.x-b.x)==0&&cmp(a.y-b.y)==0;
}
friend point operator *(const point &a,const double &b)
{
return point(a.x*b,a.y*b);
}
friend point operator *(const double &a,const point &b)
{
return point(a*b.x,a*b.y);
}
friend point operator /(const point &a,const double &b)
{
return point(a.x/b,a.y/b);
}
double norm()
{
return sqrt(sqr(x)+sqr(y));
}
};
double det(const point &a,const point &b)//計算兩個向量的叉積
{
return a.x*b.y-a.y*b.x;
}
double dot(const point &a,const point &b)//計算兩個向量的點積
{
return a.x*b.x+a.y*b.y;
}
double dist(const point &a,const point &b)
{
return (a-b).norm();
}
point rotate_point(const point &p,double A)//向量op繞原點逆時針旋轉弧度A
{
double tx=p.x,ty=p.y;
return point(tx*cos(A)-ty*sin(A),tx*sin(A)+ty*cos(A));
}
double abs(const point &o)
{
return sqrt(dot(o,o));
}
double mysqrt(double n)
{
return sqrt(max(0.0,n));
}
void circle_cross_line(point a,point b,point o,double r,point res[],int &num)//求圓與線段(直線)的交點
{
double x0=o.x,y0=o.y;
double x1=a.x,y1=a.y;
double x2=b.x,y2=b.y;
double dx=x2-x1,dy=y2-y1;
double A=dx*dx+dy*dy;
double B=2*dx*(x1-x0)+2*dy*(y1-y0);
double C=sqr(x1-x0)+sqr(y1-y0)-sqr(r);
double delta=B*B-4*A*C;
num=0;
if(cmp(delta)>=0)
{
double t1=(-B-mysqrt(delta))/(2*A);
double t2=(-B+mysqrt(delta))/(2*A);
if(cmp(t1-1)<=0&&cmp(t1)>=0)
res[num++]=point(x1+t1*dx,y1+t1*dy);
if(cmp(t2-1)<=0&&cmp(t2)>=0)
res[num++]=point(x1+t2*dx,y1+t2*dy);
}
}
point crosspt(const point &a,const point &b,const point &p,const point &q)
{
double a1=det(b-a,p-a);
double a2=det(b-a,q-a);
return (p*a2-q*a1)/(a2-a1);
}
point res[maxn];//逆時針存入多邊形的所有點
double r;//圓的半徑
int n;//多邊形點的個數
double sector_area(const point &a,const point &b)
{
double theta=atan2(a.y,a.x)-atan2(b.y,b.x);
while(theta<=0) theta+=2*pi;
while(theta>2*pi) theta-=2*pi;
theta=min(theta,2*pi-theta);
return r*r*theta/2;
}
double calc(const point &a,const point &b)
{
point p[2];
int num=0;
int ina=cmp(abs(a)-r)<0;
int inb=cmp(abs(b)-r)<0;
if(ina)
{
if(inb)
return fabs(det(a,b))/2.0;
else
{
circle_cross_line(a,b,point(0,0),r,p,num);
return sector_area(b,p[0])+fabs(det(a,p[0]))/2.0;
}
}
else
{
if(inb)
{
circle_cross_line(a,b,point(0,0),r,p,num);
return sector_area(p[0],a)+fabs(det(p[0],b))/2.0;
}
else
{
circle_cross_line(a,b,point(0,0),r,p,num);
if(num==2)
return sector_area(a,p[0])+sector_area(p[1],b)+fabs(det(p[0],p[1]))/2.0;
else return sector_area(a,b);
}
}
}
double area()//圓與多邊形的交的面積
{
double ret=0;
for(int i=0;i<n;i++)
{
int sgn=cmp(det(res[i],res[i+1]));
if(sgn!=0)
{
ret+=sgn*calc(res[i],res[i+1]);
}
}
return ret;
}//需要保證res[n]=res[0]
void circle_center(point p0,point p1,point p2,point &cp)
{
double a1=p1.x-p0.x,b1=p1.y-p0.y,c1=(a1*a1+b1*b1)/2;
double a2=p2.x-p0.x,b2=p2.y-p0.y,c2=(a2*a2+b2*b2)/2;
double d=a1*b2-a2*b1;
cp.x=p0.x+(c1*b2-c2*b1)/d;
cp.y=p0.y+(a1*c2-a2*c1)/d;
}
void circle_center(point p0,point p1,point &cp)
{
cp.x=(p0.x+p1.x)/2;
cp.y=(p0.y+p1.y)/2;
}
point center;//最小覆蓋圓的圓心
double radius;//最小覆蓋圓的半徑
bool point_in(const point &p)
{
return cmp((p-center).norm()-radius)<0;
}
void min_circle_cover(point a[],int n)//O(n)求一個半徑最小的圓覆蓋住所有的點
{
radius=0;
center=a[0];
for(int i=1;i<n;i++)
{
if(!point_in(a[i]))
{
center=a[i];
radius=0;
for(int j=0;j<i;j++)
{
if(!point_in(a[j]))
{
circle_center(a[i],a[j],center);
radius=(a[j]-center).norm();
for(int k=0;k<j;k++)
{
if(!point_in(a[k]))
{
circle_center(a[i],a[j],a[k],center);
radius=(a[k]-center).norm();
}
}
}
}
}
}
}
point rotate(const point &p,double cost,double sint)//將向量p旋轉一定弧度得到的向量(cost和sint爲弧度的cos和sin值)
{
double x=p.x,y=p.y;
return point(x*cost-y*sint,x*sint+y*cost);
}
pair<point,point> crosspoint(point ap,double ar,point bp,double br)
{
double d=(ap-bp).norm();
double cost=(ar*ar+d*d-br*br)/(2*ar*d);
double sint=sqrt(1.0-cost*cost);
point v=(bp-ap)/(bp-ap).norm()*ar;
return make_pair(ap+rotate(v,cost,-sint),ap+rotate(v,cost,sint));
}//需要確定兩圓存在交點
namespace getunion
{
const int maxN=maxn*maxn+3*maxn;
struct Tcir
{
double r;
point o;
void read()
{
scanf("%lf%lf%lf",&o.x,&o.y,&r);
}
};
struct Tinterval
{
double x,y,Area,mid;
int type;
Tcir owner;
void area(double l,double r)
{
double len=sqrt(sqr(l-r)+sqr(x-y));
double d=sqrt(sqr(owner.r)-sqr(len)/4.0);
double angle=atan(len/2.0/d);
Area=fabs(angle*sqr(owner.r)-d*len/2.0);
}
}inter[maxn];
double x[maxN],l,r;
int n,N,Nn;
bool cmpR(const Tcir &a,const Tcir &b)
{
return a.r>b.r;
}
void Get(Tcir owner,double x,double &l,double &r)
{
double y=fabs(owner.o.x-x);
double d=sqrt(fabs(sqr(owner.r)-sqr(y)));
l=owner.o.y+d;
r=owner.o.y-d;
}
void Get_interval(Tcir owner,double l,double r)
{
Get(owner,l,inter[Nn].x,inter[Nn+1].x);
Get(owner,r,inter[Nn].y,inter[Nn+1].y);
Get(owner,(l+r)/2.0,inter[Nn].mid,inter[Nn+1].mid);
inter[Nn].owner=inter[Nn+1].owner=owner;
inter[Nn].area(l,r);inter[Nn+1].area(l,r);
inter[Nn].type=1;inter[Nn+1].type=-1;
Nn+=2;
}
bool comp(const Tinterval &a,const Tinterval &b)
{
return a.mid>b.mid+eps;
}
void Add(double xx)
{
x[N++]=xx;
}
double dist2(const point &a,const point &b)
{
return sqr(dist(a,b));
}
double getunion(int n,Tcir a[])//複雜度O(n^3logn)求圓的面積並(離散化思想)
{
int p=0;
sort(a,a+n,cmpR);
for(int i=0;i<n;i++)
{
bool f1=true;
for(int j=0;j<i;j++)
{
if(dist2(a[i].o,a[j].o)<=sqr(a[i].r-a[j].r)+1e-12)
{
f1=false;
break;
}
}
if(f1)
a[p++]=a[i];
}
n=p;
N=0;
for(int i=0;i<n;i++)
{
Add(a[i].o.x-a[i].r);
Add(a[i].o.x+a[i].r);
Add(a[i].o.x);
for(int j=i+1;j<n;j++)
{
if(dist2(a[i].o,a[j].o)<=sqr(a[i].r+a[j].r)+eps)
{
pair<point,point> cross=crosspoint(a[i].o,a[i].r,a[j].o,a[j].r);
Add(cross.first.x);
Add(cross.second.x);
}
}
}
sort(x,x+N);
p=0;
for(int i=0;i<N;i++)
{
if(!i||fabs(x[i]-x[i-1])>eps)
x[p++]=x[i];
}
N=p;
double ans=0;
for(int i=0;i+1<N;i++)
{
l=x[i],r=x[i+1];
Nn=0;
for(int j=0;j<n;j++)
{
if(fabs(a[j].o.x-l)<a[j].r+eps&&fabs(a[j].o.x-r)<a[j].r+eps)
Get_interval(a[j],l,r);
}
if(Nn)
{
sort(inter,inter+Nn,comp);
int cnt=0;
for(int i=0;i<Nn;i++)
{
if(cnt>0)
{
ans+=(fabs(inter[i-1].x-inter[i].x)+fabs(inter[i-1].y-inter[i].y))*(r-l)/2.0;
ans+=inter[i-1].type*inter[i-1].Area;
ans-=inter[i].type*inter[i].Area;
}
cnt+=inter[i].type;
}
}
}
return ans;
} }
namespace fenge
{
struct Circle
{
point p;
double r;
bool operator<(const Circle &o)const
{
if(cmp(r-o.r)!=0)
return cmp(r-o.r)==-1;
if(cmp(p.x-o.p.x)!=0)
{
return cmp(p.x-o.p.x)==-1;
}
return cmp(p.y-o.p.y)==-1;
}
bool operator==(const Circle &o)const
{
return cmp(r-o.r)==0&&cmp(p.x-o.p.x==0)&&cmp(p.y-o.p.y)==0;
}
};
inline pair<point,point> crosspoint(const Circle &a,const Circle &b)
{
return crosspoint(a.p,a.r,b.p,b.r);
}
Circle c[maxn],tc[maxn];
int n,m;
struct Node
{
point p;
double a;
int d;
Node(const point &p,double a,int d):p(p),a(a),d(d){}
bool operator<(const Node &o)const
{
return a<o.a;
}
};
double arg(point p)
{
return arg(complex<double>(p.x,p.y));
}
double solve()////複雜度O(m^2logm)求圓的面積並(分割的思想)
{
sort(tc,tc+m);
m=unique(tc,tc+m)-tc;
for(int i=m-1;i>=0;i--)
{
bool ok=true;
for(int j=i+1;j<m;j++)
{
double d=(tc[i].p,tc[j].p).norm();
if(cmp(d-abs(tc[i].r-tc[j].r))<=0)
{
ok=false;
break;
}
}
if(ok)
c[n++]=tc[i];
}
double ans=0;
for(int i=0;i<n;i++)
{
vector<Node> event;
point boundary=c[i].p+point(-c[i].r,0);
event.push_back(Node(boundary,-pi,0));
event.push_back(Node(boundary,pi,0));
for(int j=0;j<n;j++)
{
if(i==j) continue;
double d=(c[i].p-c[j].p).norm();
if(cmp(d-(c[i].r+c[j].r))<0)
{
pair<point,point> ret=crosspoint(c[i],c[j]);
double x=arg(ret.first-c[i].p);
double y=arg(ret.second-c[i].p);
if(cmp(x-y)>0)
{
event.push_back(Node(ret.first,x,1));
event.push_back(Node(boundary,pi,-1));
event.push_back(Node(boundary,-pi,1));
event.push_back(Node(ret.second,y,-1));
}
else
{
event.push_back(Node(ret.first,x,1));
event.push_back(Node(ret.second,y,-1));
}
}
}
sort(event.begin(),event.end());
int sum=event[0].d;
for(int j=1;j<(int)event.size();j++)
{
if(sum==0)
{
ans+=det(event[j-1].p,event[j].p)/2;
double x=event[j-1].a;
double y=event[j].a;
double area=c[i].r*c[i].r*(y-x)/2;
point v1=event[j-1].p-c[i].p;
point v2=event[j].p-c[i].p;
area-=det(v1,v2)/2;
ans+=area;
}
sum+=event[j].d;
}
}
return ans;
} }