题解 「BZOJ2178」圆的面积并
题目大意
给出 \(n\) 个圆,求它们并的面积大小。
\(n\le 10^3\)
思路
如果您不会自适应辛普森法,请戳这里学习
其实我们发现,如果我们设 \(f(x)\) 表示 \(x=x\) 这条直线与所有圆的交的线段的长度,那么答案就是:
\[\int^{+\infty}_{-\infty}f(x),dx
\]
然后你发现 \(f(x)\) 可以在 \(\Theta(n)\) 的时间复杂度内解决,而实际上范围也达不到 \(\infty\),实际操作中直接取 \(2000\) 就可以了(实际上你按圆的左右边界来做自适应辛普森法会有一个小小的误差)
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define double long double
#define Int register int
#define MAXN 1005
#define eps 1e-12
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,top;
struct Cir{double x,y,r;}a[MAXN];
struct Line{
double l,r;
bool operator < (const Line &p)const{return l < p.l;}
}p[MAXN];
double Sqr (double x){return x * x;}
double f (double x){//这些园跟x=x交的长度
top = 0;
for (Int i = 1;i <= n;++ i)
if (a[i].x - a[i].r <= x && x <= a[i].x+ a[i].r){
double len = sqrt (Sqr (a[i].r) - Sqr (a[i].x - x));
p[++ top] = Line {a[i].y - len,a[i].y + len};
}
sort (p + 1,p + top + 1);
double ret = 0,l = -1e9,r = -1e9;
for (Int i = 1;i <= top;++ i)
if (p[i].l - r > eps) ret += r - l,l = p[i].l,r = p[i].r;
else if (p[i].r - r > eps) r = p[i].r;
return ret + r - l;
}
double Simpson (double l,double r){return (r - l) * (f (l) + f(r) + 4.0 * f ((l + r) / 2)) / 6;}
double asr (double l,double r,double ans){//储存ans纯粹是为了卡常
double mid = (l + r) / 2,lans = Simpson (l,mid),rans = Simpson (mid,r);
if (fabs (lans + rans - ans) < eps) return ans;
else return asr (l,mid,lans) + asr (mid,r,rans);
}
double asr (double l,double r){return asr (l,r,Simpson (l,r));}
signed main(){
read (n);
for (Int i = 1;i <= n;++ i) scanf ("%Lf%Lf%Lf",&a[i].x,&a[i].y,&a[i].r);
double l = 1e9,r = -1e9;
for (Int i = 1;i <= n;++ i) l = min (l,a[i].x - a[i].r),r = max (r,a[i].x + a[i].r);
printf ("%.3Lf\n",asr (l+eps,r-eps));
return 0;
}