傳送門:bzoj2178
題解
誤差在內就返回
並查集分別處理每個圓的連通塊的積分,單點值掃描線算一下就好了。
p.s
心情複雜,我的掃描線多了2倍的常數T了,然後從改到剛好能挽回2的常數,然後又WA了。
換了一種掃描線才過(注意常數,eps需要設的很小)
代碼
//bzoj2178 圓的面積並
#include<bits/stdc++.h>
using namespace std;
typedef double db;
const db eps=1e-13,inf=2e9;
const int N=1010;
int n,m,f[N],cot;bool vs[N];db ans;
db xl[N],xr[N];
struct o{db x,y,r;}p[N],q[N];
//struct ap{db x;int v;}c[N<<1];
struct ap{db x,y;}c[N<<1];
inline int getfa(int x){return x==f[x]?x:(f[x]=getfa(f[x]));}
inline bool cmpr(o a,o b){return a.r<b.r;}
inline bool cmpx(o a,o b){return a.x-a.r<b.x-b.r;}
inline bool cmpy(ap a,ap b){return a.x<b.x;}
inline db sqr(db x){return x*x;}
inline db dist(o a,o b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
inline db calc(db len,db fl,db fmid,db fr)
{return len*(fl+fr+4.0*fmid)/6.0;}
db F(db pos)
{
int i,j;db dis,re=0;cot=0;
for(i=1;i<=m;++i){
if(pos>=xr[i]) continue;
if(pos<=xl[i]) break;
dis=sqrt(q[i].r-(q[i].x-pos)*(q[i].x-pos));
// c[++cot]=(ap){q[i].y-dis,1};
// c[++cot]=(ap){q[i].y+dis,-1};
c[++cot]=(ap){q[i].y-dis,q[i].y+dis};
}
sort(c+1,c+cot+1,cmpy);
for(j=0,i=1;i<=cot;++i){
// if(j>0) re+=(c[i].x-c[i-1].x);
// j+=c[i].v;
dis=c[i].y;
for(j=i;j<cot && c[j+1].x<=dis;++j) dis=max(dis,c[j+1].y);
re+=dis-c[i].x;i=j;
}
return re;
}
db simpson(db l,db mid,db r,db fl,db fmid,db fr,db s)
{
db lmid=(l+mid)/2.0,rmid=(mid+r)/2.0;
db ffl=F(lmid),ffr=F(rmid),a=calc(mid-l,fl,ffl,fmid),b=calc(r-mid,fmid,ffr,fr);
if(fabs(a+b-s)<eps) return a+b;
return simpson(l,lmid,mid,fl,ffl,fmid,a)+simpson(mid,rmid,r,fmid,ffr,fr,b);
}
int main(){
// freopen("simpson.in","r",stdin);
int i,j,k;db l,r,mid,fl,fr,fmid;scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r);
sort(p+1,p+n+1,cmpr);
for(i=1;i<=n;++i){
for(j=n;j>i;--j)
if(dist(p[i],p[j])<=p[j].r-p[i].r) break;
if(j<=i) p[++m]=p[i];
}
n=m;
for(i=1;i<=n;++i) f[i]=i;
for(i=1;i<n;++i)
for(j=i+1;j<=n;++j)
if(getfa(i)!=getfa(j) && dist(p[i],p[j])<=p[i].r+p[j].r)
f[getfa(j)]=getfa(i);
for(i=1;i<=n;++i) getfa(i);
for(i=1;i<=n;++i) if(!vs[f[i]]){
m=0;k=f[i];vs[k]=true;l=inf;r=-inf;
for(j=i;j<=n;++j) if(f[j]==k) {
q[++m]=p[j];
l=min(l,p[j].x-p[j].r);r=max(r,p[j].x+p[j].r);
}
sort(q+1,q+m+1,cmpx);
for(j=1;j<=m;++j){
xl[j]=q[j].x-q[j].r,xr[j]=q[j].x+q[j].r;
q[j].r*=q[j].r;
}
mid=(l+r)/2.0;fl=F(l);fr=F(r);fmid=F(mid);
ans+=simpson(l,mid,r,fl,fmid,fr,calc(r-l,fl,fmid,fr));
}
printf("%.3lf",ans);
return 0;
}