【bzoj4561】【JLOI2016】【圆的异或并】【扫描线+set】

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

Sample Output

3
题解:
对于一个圆,拆出它的左端点和右端点.
按这些点的横坐标排序.然后扫这些点.
扫到一个左端点就计算这个圆产生的贡献是正的还是负的.
这个可以每次找第一个包含这个圆的圆或者和它并列的圆.
用set维护一下当前所有圆在这个左端点的横坐标上的纵坐标就可以实现.

代码:

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<set>  
#include<cmath>  
#include<algorithm>  
#define N 200010  
#define ll long long  
using namespace std;  
struct cir{ll x,y,r;}c[N];  
struct use{int p,x,k;}q[N<<1];  
int n;  
set<use>s;  
ll temp,g[N],ans;  
ll cal(ll x){return x*x;}  
bool cmp(use a,use b){return a.x<b.x;}  
bool operator<(use a,use b){  
  double x=c[a.p].y+a.k*sqrt(cal(c[a.p].r)-cal(temp-c[a.p].x));  
  double y=c[b.p].y+b.k*sqrt(cal(c[b.p].r)-cal(temp-c[b.p].x));  
  if (x!=y) return x<y;  
  else return a.k<b.k;  
}  
int main(){  
  scanf("%d",&n);  
  for (int i=1;i<=n;i++){  
    scanf("%lld%lld%lld",&c[i].x,&c[i].y,&c[i].r);  
    q[(i<<1)-1]=use{i,c[i].x-c[i].r,1};  
    q[i<<1]={i,c[i].x+c[i].r,-1};  
  }   
  sort(q+1,q+(n<<1)+1,cmp);  
  for (int i=1;i<=(n<<1);i++){  
    temp=q[i].x;  
    if (q[i].k==1){  
      set<use>::iterator it;  
      it=s.upper_bound(use{q[i].p,0,-1});  
      if (it==s.end()) g[q[i].p]=1;  
      else{  
        if ((*it).k==-1) g[q[i].p]=g[(*it).p];  
        else g[q[i].p]=-g[(*it).p];  
      }  
      s.insert(use{q[i].p,0,1});s.insert(use{q[i].p,0,-1});  
    }  
    else{  
      s.erase(use{q[i].p,0,1});s.erase(use{q[i].p,0,-1});     
    }  
  }  
  for (int i=1;i<=n;i++)  
    ans+=cal(c[i].r)*g[i];  
  cout<<ans<<endl;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值