[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;
}