[BZOJ4561][JLOI2016]圆的异或并(扫描线)
考虑任何一条垂直于x轴的直线,由于圆不交,所以这条直线上的圆弧构成形似括号序列的样子,且直线移动时圆之间的相对位置不变。
将每个圆拆成两边,左端加右端删。每次加圆时考虑它外面最内层的括号属于谁。用set维护括号序列,每次从插入的位置往上找,如果第一个找到的是上括弧则说明被它包含,如果是下括弧说明和它并列。这样每个圆的符号就可以确定了。
1 #include<set> 2 #include<cmath> 3 #include<cstdio> 4 #include<algorithm> 5 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 6 typedef long long ll; 7 using namespace std; 8 9 const int N=400010; 10 int n,tmp,f[N]; 11 ll ans,x[N],y[N],r[N]; 12 13 struct P{ int x,f,id; }q[N]; 14 double gety(int id,int p,int k) 15 { return y[id]+k*sqrt(r[id]*r[id]-(x[id]-p)*(x[id]-p)); } 16 17 struct D{ int id,k; }; 18 bool operator <(const D &a,const D &b){ 19 return (a.id==b.id) ? a.k<b.k : gety(a.id,tmp,a.k)<gety(b.id,tmp,b.k); 20 } 21 22 set<D> S; 23 bool cmp(const P &a,const P &b){ return a.x==b.x ? a.f<b.f : a.x<b.x; } 24 25 int main(){ 26 freopen("bzoj4561.in","r",stdin); 27 freopen("bzoj4561.out","w",stdout); 28 scanf("%d",&n); 29 rep(i,1,n){ 30 scanf("%lld%lld%lld",&x[i],&y[i],&r[i]); 31 q[2*i-1]=(P){x[i]-r[i],1,i}; q[2*i]=(P){x[i]+r[i],-1,i}; 32 } 33 sort(q+1,q+2*n+1,cmp); 34 rep(i,1,2*n){ 35 if (q[i].f==-1) S.erase((D){q[i].id,1}),S.erase((D){q[i].id,-1}); 36 else{ 37 tmp=q[i].x; set<D>::iterator it=S.lower_bound((D){q[i].id,1}); 38 if (it!=S.end()) f[q[i].id]=((it->k==1)?-1:1)*f[it->id]; 39 else f[q[i].id]=1; 40 S.insert((D){q[i].id,1}); S.insert((D){q[i].id,-1}); 41 } 42 } 43 rep(i,1,n) ans+=f[i]*r[i]*r[i]; 44 printf("%lld\n",ans); 45 return 0; 46 }