1. 程式人生 > >bzoj 2178 圓的面積並【simpson積分】

bzoj 2178 圓的面積並【simpson積分】

double gpo max 直接 code clu 維護 tdi 面積並

直接套simpson,f可以直接把圓排序後掃一遍所有圓,這樣維護一個區間就可以避免空段。
然而一定要去掉被其他圓完全覆蓋的圓,否則會TLE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-13;
const int N=1005;
int n,m;
double mn=1e13,mx=-1e13;
bool fl[N];
struct cir
{
    double x,y,r;
    double
operator < (const cir &a) const { return r<a.r; } }c[N]; struct qwe { double l,r; qwe(double L=0,double R=0) { l=L,r=R; } bool operator < (const qwe &a) const { return l<a.l; } }a[N]; int cmp(double x) { if(x<=eps&&x>=-eps) return
0; return x>0?1:-1; } double f(double x) { int cnt=0; for(int i=1;i<=n;i++) { double dis=fabs(c[i].x-x); if(cmp(dis-c[i].r)<0) { double len=sqrt(c[i].r*c[i].r-dis*dis); a[++cnt]=qwe(c[i].y-len,c[i].y+len); } } if(!cnt) return
0; sort(a+1,a+1+cnt); double l=a[1].l,r=a[1].r,ans=0; for(int i=2;i<=cnt;i++) { if(cmp(a[i].l-r)<=0) r=max(r,a[i].r); else ans+=r-l,l=a[i].l,r=a[i].r; } ans+=r-l; return ans; } double sps(double l,double r,double now,double fl,double fr,double fm) { double mid=(l+r)/2,ffl=f((l+mid)/2),ffr=f((mid+r)/2),p=(fl+fm+ffl*4)*(mid-l)/6,q=(fm+fr+ffr*4)*(r-mid)/6; if(cmp(now-p-q)==0) return now; else return sps(l,mid,p,fl,fm,ffl)+sps(mid,r,q,fm,fr,ffr); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r); mn=min(mn,c[i].x-c[i].r),mx=max(mx,c[i].x+c[i].r); }//cout<<"OK"<<endl; sort(c+1,c+1+n); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(cmp(sqrt((c[i].x-c[j].x)*(c[i].x-c[j].x)+(c[i].y-c[j].y)*(c[i].y-c[j].y))+c[i].r-c[j].r)<=0) { fl[i]=1; break; } for(int i=1;i<=n;i++) if(!fl[i]) c[++m]=c[i]; n=m; double fl=f(mn),fr=f(mx),fm=f((mn+mx)/2); printf("%.3lf\n",sps(mn,mx,(fl+4*fm+fr)*(mx-mn)/6,fl,fr,fm)); return 0; }

bzoj 2178 圓的面積並【simpson積分】