计数方法(扫描线):JLOI 2016 圆的异或并
Posted 既然选择了远方,便只顾风雨兼程
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计数方法(扫描线):JLOI 2016 圆的异或并相关的知识,希望对你有一定的参考价值。
Description
在平面直角坐标系中给定N个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面
积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
Input
第一行包含一个正整数N,代表圆的个数。接下来N行,每行3个非负整数x,y,r,表示一个圆心在(x,y),半径为r的
圆。保证|x|,|y|,≤10^8,r>0,N<=200000
Output
仅一行一个整数,表示所有圆的异或面积并除以圆周率Pi的结果。
Sample Input
2
0 0 1
0 0 2
0 0 1
0 0 2
Sample Output
3
这道题是模板题,经典题。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <cmath> 6 #include <set> 7 8 #include <cassert> 9 using namespace std; 10 const int N=200010,M=600010; 11 int n,px[N],py[N],r[N],top,T; 12 long long sqr(long long a){return a*a;} 13 struct Point{ 14 int id,x,tp; 15 friend bool operator<(Point x,Point y){ 16 double a=py[x.id]+x.tp*sqrt(sqr(r[x.id])-sqr(T-px[x.id])); 17 double b=py[y.id]+y.tp*sqrt(sqr(r[y.id])-sqr(T-px[y.id])); 18 if(a!=b)return a<b;assert(x.id==y.id);return x.tp<y.tp; 19 } 20 }st[M]; 21 bool cmp(Point a,Point b){ 22 return a.x<b.x; 23 } 24 int res[N]; 25 set<Point>s; 26 set<Point>::iterator it; 27 long long ans; 28 29 30 int main(){ 31 freopen("circle.in","r",stdin); 32 freopen("circle.out","w",stdout); 33 scanf("%d",&n); 34 for(int i=1;i<=n;i++){ 35 scanf("%d%d%d",&px[i],&py[i],&r[i]); 36 st[++top]=(Point){i,px[i]-r[i],1}; 37 st[++top]=(Point){i,px[i]+r[i],-1}; 38 } 39 40 sort(st+1,st+top+1,cmp); 41 for(int i=1;i<=top;i++){ 42 Point x=st[i];T=x.x; 43 if(x.tp==1){ 44 it=s.upper_bound((Point){x.id,0,1}); 45 if(it==s.end())res[x.id]=1; 46 else{ 47 Point y=*it; 48 if(y.tp==1)res[x.id]=-res[y.id]; 49 else res[x.id]=res[y.id]; 50 } 51 s.insert((Point){x.id,0,-1}); 52 s.insert((Point){x.id,0,1}); 53 } 54 else{ 55 s.erase((Point){x.id,0,-1}); 56 s.erase((Point){x.id,0,1}); 57 } 58 } 59 for(int i=1;i<=n;i++) 60 ans+=res[i]*sqr(r[i]); 61 printf("%lld\n",ans); 62 return 0; 63 }
以上是关于计数方法(扫描线):JLOI 2016 圆的异或并的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ4561:圆的异或并(扫描线+set||splay||线段树)