Skip to content

自适应辛普森积分求圆的面积并 ​

cpp
const double eps=1e-12;
int n;
struct Point{
    double x,y;
    bool operator<(const Point &t)const{
        return x!=t.x?x<t.x:y<t.y;
    }
};
struct Circle{
    Point p;
    double R;
} c[N];
Point q[N];
int dcmp(double x,double y){
    if(fabs(x-y)<eps)return 0;
    if(x<y)return -1;
    return 1;
}
double f(double x){
    int cnt=0;
    for(int i=0;i<n;i++){
        double X=fabs(x-c[i].p.x),R=c[i].R;
        if(dcmp(X,R)<0){
            double Y=sqrt(R*R-X*X);
            q[cnt++]={c[i].p.y-Y,c[i].p.y+Y};
        }
    }
    if(!cnt)return 0;
    sort(q,q+cnt);
    double res=0,st=q[0].x,ed=q[0].y;
    for(int i=1;i<cnt;i++){
        if(q[i].x<=ed)ed=max(ed,q[i].y);
        else{
            res+=ed-st;
            st=q[i].x,ed=q[i].y;
        }
    }
    return res+ed-st;
}

double simpson(double l,double r,double sl,double sr){
    double mid=(l+r)/2;
    return (r-l)*(sl+4*f(mid)+sr)/6;
}
double asr(double l,double r,double s,double sl,double sr){
    double mid=(l+r)/2;
    double S=f(mid);
    double left=simpson(l,mid,sl,S),right=simpson(mid,r,S,sr);
    if(fabs(left+right-s)<eps)return left+right;
    return asr(l,mid,left,sl,S)+asr(mid,r,right,S,sr);
}
double dis(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
void init(){		//预处理,删除被包含的圆
    int cnt = 0;
    for (int i = 0, j; i < n; ++i) {
        for (j = i+1; j < n; ++j) {
            if(c[i].R-c[j].R + dis(c[i].p, c[j].p) < eps){
                break;
            }
        }
        if(j >= n) c[cnt++] = c[i];
    }
    n = cnt;
}
vector<Point> segs;
void merge(){
    sort(segs.begin(),segs.end());
    vector<Point> res;
    double st=segs[0].x,ed=segs[0].y;
    for(int i=1;i<segs.size();i++){
        if(dcmp(segs[i].x,ed)<=0)ed=max(ed,segs[i].y);
        else{
            res.push_back({st,ed});
            st=segs[i].x,ed=segs[i].y;
        }
    }
    res.push_back({st,ed});
    segs.swap(res);
}
void solve(){
    cin>>n;
    for(int i=0;i<n;i++)cin>>c[i].p.x>>c[i].p.y>>c[i].R,segs.push_back({c[i].p.x - c[i].R, c[i].p.x + c[i].R});
    sort(c,c+n,[&](Circle a,Circle b){
        return a.R<b.R;
    });
    init();
    merge();
    double res=0;
    for(int i=0;i<segs.size();i++){
        auto [l,r]=segs[i];
        res+=asr(l,r,f((l+r)/2),f(l),f(r));
    }
    cout<<setprecision(3)<<fixed<<res<<"\n";
}