Description
在平面直角坐标系中给定N个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面
积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
Input
第一行包含一个正整数N,代表圆的个数。接下来N行,每行3个非负整数x,y,r,表示一个圆心在(x,y),半径为r的
圆。保证|x|,|y|,≤10^8,r>0,N<=200000
Output
仅一行一个整数,表示所有圆的异或面积并除以圆周率Pi的结果。
用平衡树维护扫描线与圆的交点
#include<cstdio> #include<cmath> #include<algorithm> #include<set> typedef long long i64; const int N=200010; int n; i64 xs[N],ys[N],rs[N],X; inline i64 p2(i64 x){return x*x;} inline int _int(){ int x=0,c=getchar(),f=1; while(c>57||c<48){if(c=='-')f=-1;c=getchar();} while(c>47&&c<58)x=x*10+c-48,c=getchar(); return x*f; } struct pos{ i64 x,y; int sgn,dep; i64 r; double Y(){ i64 a=r-p2(x-X); if(a<0)return y; return y+sgn*sqrt(a); } }; bool operator<(pos a,pos b){ double x=a.Y(),y=b.Y(); if(fabs(x-y)>=.5)return x<y; return a.sgn<b.sgn; } struct event{ bool in; int id; i64 x(){ if(in)return xs[id]-rs[id]; else return xs[id]+rs[id]; } }e[N*2]; bool operator<(event a,event b){ i64 c=a.x(),d=b.x(); if(c!=d)return c<d; return a.in<b.in; } std::set<pos>line; int deps[N]; int xp; i64 xv[N*2]; int main(){ n=_int(); for(int i=0;i<n;i++){ xs[i]=_int();ys[i]=_int();rs[i]=_int(); xv[i*2]=(e[i*2]=(event){1,i}).x(); xv[i*2+1]=(e[i*2+1]=(event){0,i}).x(); } std::sort(e,e+n*2); for(int p=0;p<n*2;++p){ int id=e[p].id,d; if(e[p].in){ X=e[p].x(); pos w=(pos){xs[id],ys[id],0,0,p2(rs[id])}; std::set<pos>::iterator it=line.upper_bound(w); if(it!=line.end()){ w=*it; d=(w.sgn==1?-w.dep:w.dep); }else d=1; line.insert((pos){xs[id],ys[id],1,d,p2(rs[id])}); line.insert((pos){xs[id],ys[id],-1,d,p2(rs[id])}); deps[id]=d; }else{ X=e[p].x(); line.erase(line.find((pos){xs[id],ys[id],1,0,p2(rs[id])})); line.erase(line.find((pos){xs[id],ys[id],-1,0,p2(rs[id])})); } } i64 ans=0; for(int i=0;i<n;i++)ans+=rs[i]*rs[i]*deps[i]; printf("%lld\n",ans); return 0; }