圆的面积并

以前以为圆的面积并只能辛普森积分。今天才知道原来可以\(O(n^2\log n)\)做。
大致思路是对每个圆求出不与其他圆重合的角度区域,加上这个角度对应的弓形面积,并且加上这段区域边界两个点的叉积的\(\frac{1}{2}\)
仔细画一画图发现这恰好是对的。非常神奇qwq 证明
代码如下

double sqr(double x){return x*x;}
struct vec{
	double x,y;
	vec operator+ (const vec b) const{return (vec){x+b.x,y+b.y};}
	vec operator- (const vec b) const{return (vec){x-b.x,y-b.y};}
	vec operator* (const double b) const{return (vec){x*b,y*b};}
	double operator* (const vec b) const{return x*b.x+y*b.y;}
	double operator^ (const vec b) const{return x*b.y-y*b.x;}
	double norm(){return sqrt(sqr(x)+sqr(y));}
	double norm2(){return sqr(x)+sqr(y);}
	double ang(){return atan2(y,x);}
}P[M];
vec go(vec x,double k,double r){return (vec){x.x+r*cos(k),x.y+r*sin(k)};}
double calc(int key){
	if (R[key]<1e-9) return 0;double ans=0;int sum=0;
	static std::pair <double,int> Tag[M];int cnt=0;
	for (register int i=1;i<=n;i++){
		if (i==key||R[i]<1e-9) continue;
		double len=(P[i]-P[key]).norm();
		if (R[i]<R[key]&&len<=R[key]-R[i]) continue;
		if (R[i]>R[key]&&len<=R[i]-R[key]) return 0;
		if (R[i]+R[key]<=len) continue;
		double mid=(P[i]-P[key]).ang();
		double ang=acos((sqr(R[key])+sqr(len)-sqr(R[i]))/(2*len*R[key]));
		double ml=mid-ang,mr=mid+ang;if (ml<-pi) ml+=2*pi;if (mr>pi) mr-=2*pi;
		Tag[++cnt]=std::make_pair(ml,1),Tag[++cnt]=std::make_pair(mr,-1);
		if (ml>mr) ++sum;
	}
	Tag[++cnt]=std::make_pair(-pi,0),Tag[++cnt]=std::make_pair(pi,1);
	std::sort(Tag+1,Tag+1+cnt);
	for (register int i=1,j=1;i<=cnt;i=j){
		while (j<=cnt&&Tag[j].first-Tag[i].first<1e-8) sum+=Tag[j++].second;
		if (!sum){
			double ang=Tag[j].first-Tag[i].first;
			ans+=sqr(R[key])*(ang-sin(ang))+(go(P[key],Tag[i].first,R[key])^go(P[key],Tag[j].first,R[key]));
		}
	}
	return ans;
}
double Sum(){double ans=0;for (register int i=1;i<=n;i++) ans+=calc(i);return ans/2;}

这个东西再套个辛普森积分就可以求球的面积并了。

posted @ 2020-07-11 23:38  Binary_Search_Tree  阅读(472)  评论(0编辑  收藏  举报