[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 }

 

posted @ 2018-12-04 00:16  HocRiser  阅读(168)  评论(0编辑  收藏  举报