[BZOJ2178] 圆的面积并

Description

给出N个圆,求其面积并

Input

先给一个数字N ,N< = 1000 接下来是N行是圆的圆心,半径,其绝对值均为小于1000的整数

Output

面积并,保留三位小数

Solution

直接套\(simpson\)积分板子就好了,判掉圆包含的情况,然后每次求\(f(x)\)的时候直接枚举所有的圆然后扫描线暴力搞,因为积分的意义下\(f(a)\)的几何意义就是\(x=a\)被图形覆盖的长度。

#include<bits/stdc++.h>
using namespace std;
 
void read(int &x) {
    x=0;int f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
 
void print(int x) {
    if(x<0) putchar('-'),x=-x;
    if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');}

#define lf double
#define ll long long 

const int maxn = 1e3+10;
const int inf = 1e9;
const lf eps = 1e-8;

struct C{
	int x,y,r,vis;
	int operator < (const C &rhs) const {return r<rhs.r;}
}a[maxn];
int n;

#define sqr(x) ((x)*(x))

struct asd {
	lf u,d;
	int operator < (const asd &rhs) const {return d<rhs.d||(d==rhs.d&&u<rhs.u);}
}rr[maxn];

lf f(lf x) {
	int t=0;
	for(int i=1;i<=n;i++)
		if(a[i].x-a[i].r<x&&x<a[i].x+a[i].r) {
			if(a[i].vis) continue;
			lf s=sqrt(sqr(a[i].r)-sqr(a[i].x-x));
			rr[++t]=(asd){(lf)a[i].y+s,(lf)a[i].y-s};
		}
	sort(rr+1,rr+t+1);
	lf ans=0,d=rr[1].d;
	for(int i=1;i<=t;i++) 
		if(d<rr[i].d) ans+=rr[i].u-rr[i].d,d=rr[i].u;
		else if(d<rr[i].u) ans+=rr[i].u-d,d=rr[i].u;
	return ans;
}

lf _int(lf l,lf r) {return (r-l)*(f(r)+f(l)+4.0*f((l+r)*0.5))/6.0;}

lf simpson(lf l,lf r,lf res) {
	lf mid=(l+r)*0.5,L=_int(l,mid),R=_int(mid,r);
	if(fabs(L+R-res)<eps) return L+R;
	else return simpson(l,mid,L)+simpson(mid,r,R);
}

int main() {
	read(n);
	for(int i=1;i<=n;i++) read(a[i].x),read(a[i].y),read(a[i].r);
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++)
			if(sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y)<=sqr(a[j].r-a[i].r)) {
				a[i].vis=1;break;
			}
	printf("%.3lf\n",simpson(-2000.00,2000.00,_int(-2000.00,2000.00)));
	return 0;
}
posted @ 2019-03-16 13:20  Hyscere  阅读(609)  评论(0编辑  收藏  举报