【BZOJ】2178: 圓的面積並-自適應辛普森積分

傳送門:bzoj2178


題解

在這裏插入圖片描述
誤差在epseps內就返回

並查集分別處理每個圓的連通塊的積分,單點值F(x)F(x)掃描線算一下就好了。

p.s

心情複雜,我的掃描線多了2倍的常數T了,然後epseps101310^{-13}改到101210^{-12}剛好能挽回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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章