题意:求多个圆形区域的并的面积。圆的数量
n
<
=
1000
n <= 1000
n<=1000
我们设
f
(
a
)
=
(
x
=
a
这
条
直
线
在
圆
形
区
域
内
的
长
度
)
f(a)=(x=a这条直线在圆形区域内的长度)
f(a)=(x=a这条直线在圆形区域内的长度), 那么答案就是
∫
f
(
x
)
d
x
\int f(x)\rm {d} x
∫f(x)dx
然后就可以直接用自适应辛普森积分来近似答案。
e
p
s
=
1
e
−
6
eps = 1e-6
eps=1e−6可过。
计算
f
(
x
)
f(x)
f(x)是
O
(
n
log
n
)
O(n \log n)
O(nlogn)的
但是(所以)我们需要卡常(毕竟这是玄学算法)。
1.辛普森积分在不连续的地方效率会降低,那么就把圆分成多组,每组的分别计算,因为每组内
f
f
f是连续的。
2.如果一个圆被另一个圆包含,就删掉这个圆(效果很好)。
AC Code;
#include<bits/stdc++.h>
#define maxn 1005
#define eps 1e-6
using namespace std;
int n;
struct Cir
{
double x,y,r,L,R;
bool operator <(const Cir &B)const{ return L<B.L; }
}O[maxn];
double sqr(double a){ return a*a; }
vector<Cir>C;
map<double,double>mp;
double ans = 0;
vector<pair<double,double> >st;
double f(double a)
{
if(mp.count(a)) return mp[a];
st.clear();
for(int i=0,siz=C.size();i<siz;i++)
if(fabs(C[i].x-a)<C[i].r)
{
double dis = C[i].x-a , u = sqrt(sqr(C[i].r)-sqr(dis)) , l , r;
l = C[i].y - u , r = C[i].y + u;
st.push_back(make_pair(l,r));
}
sort(st.begin(),st.end());
double mx=-0x3f3f3f3f,ret=0;
for(vector<pair<double,double> >::iterator it=st.begin();it!=st.end();it++)
{
mx = max(mx , (*it).first);
ret+=max(0.0,(*it).second-mx);
mx = max(mx , (*it).second);
}
mp[a] = ret;
return ret;
}
double calc(double a,double b,double c,double Fa,double Fb,double Fc)
{
return (Fa + 4 * Fb + Fc) / 6 * (c-a);
}
void solve(double l,double r)
{
double mid = (l+r) * 0.5,mid1=(l+mid)*0.5,mid2=(r+mid)*0.5;
double F[5]={f(l),f(mid1),f(mid),f(mid2),f(r)};
double lv = calc(l,mid1,mid,F[0],F[1],F[2]),rv=calc(mid,mid2,r,F[2],F[3],F[4]),v=calc(l,mid,r,F[0],F[2],F[4]);
if(fabs(v-lv-rv)<eps){ ans+=lv+rv;return; }
solve(l,mid),solve(mid,r);
}
bool ban[maxn];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&O[i].x,&O[i].y,&O[i].r),O[i].L=O[i].x-O[i].r,O[i].R=O[i].x+O[i].r;
sort(O+1,O+1+n);
double mx = -0x3f3f3f3f,pre;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j)
{
double dis = sqrt(sqr(O[i].x-O[j].x)+sqr(O[i].y-O[j].y));
if(O[j].r > dis)
{
if(dis + O[i].r < O[j].r - eps)
ban[i] = 1;
}
}
for(int i=1;i<=n;i++)
if(!ban[i]){
if(O[i].L>mx)
{
if(C.size())
{
solve(pre,mx);
C.clear();
mp.clear();
}
}
if(C.empty()) pre = O[i].L;
C.push_back(O[i]);
mx = max(O[i].R,mx);
}
if(C.size())
solve(pre,mx);
printf("%.3lf\n",ans);
}//asdf