传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4561
还是头一次回头写自己参加过的比赛的题
记得当时没开long long还以为要爆零。。。虽然最后还是滚粗了
言归正传
这题的算法叫扫描法,就是说把所有可能导致圆的上下关系变化的关键x值找到,然后从小到大进行扫描,找到圆的关系
这里的关键x是每个圆的水平直径的两个端点横坐标,也就是一个圆被扫到的起始和结束点
扫到圆C起始点时将C的上半圆和下半圆分别加入平衡树(set也好啊)然后找下半圆的前驱。若前驱为另一个圆O的下半圆,则C包含在O中,C计算面积时的方法与O相反(O加则C减);若前驱为O的上半圆,则C与O同级,C计算方法与O相同。特殊地,若C的下半圆没有前驱,则计算C时要加上它的面积,因为C不被任何圆包含。
//被坑了两次之后,我算是发现double比较大小有多不准了,解决方法详见代码40行
#include<cstdio> #include<set> #include<algorithm> #include<cmath> using namespace std; #define maxn 200005 #define long long long int n; double X; struct circle { long x; long y; long r; int parametre; void read(){scanf("%lld%lld%lld",&x,&y,&r);} long area(){return r*r*parametre;} double dis(){return sqrt(r*r-(x-X)*(x-X));} }full[maxn]; struct keypoint { circle *belong; long x; int end; keypoint(circle *c,int t):belong(c),end(t){x=c->x+c->r*t;} keypoint(){}; }kp[maxn*2]; struct arch { circle *belong; int type; arch(circle *c,int t):belong(c),type(t){} double y() { return (double)belong->y+belong->dis()*type; } }; bool operator < (arch a,arch b) { return ((a.y()==b.y())?a.type<b.type:a.y()<b.y()); } bool operator < (const keypoint &a, const keypoint &b){return a.x<b.x;} set<arch> arc; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { full[i].read(); kp[i*2-1]=keypoint(full+i,-1); kp[i*2]=keypoint(full+i,1); } sort(kp+1,kp+1+2*n); for(int i=1;i<=2*n;i++) { X=kp[i].x; if(kp[i].end==1) arc.erase(arch(kp[i].belong,-1)),arc.erase(arch(kp[i].belong,1)); else { arc.insert(arch(kp[i].belong,-1)); arc.insert(arch(kp[i].belong,1)); set<arch>::iterator it=arc.find(arch(kp[i].belong,-1)); if(it==arc.begin()) kp[i].belong->parametre=1; else { it--; kp[i].belong->parametre=it->type*(it->belong->parametre); } } } long ans=0; //for(int i=1;i<=n;i++) printf("%d %d\n",i,full[i].parametre); for(int i=1;i<=n;i++) ans+=full[i].area(); printf("%lld\n",ans); return 0; }