圆的异或并
bzoj 4561 圆的异或并
题意
在平面直角坐标系中给定\(N\)个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面
积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。
解法
这个很简单
因为圆两两不相交,所以其相对位置不变,所以我们将其拆为两个半圆弧,当我们碰到左端点的时候,就加入这两个圆弧,碰到右端点的时候,就将他们删去。然后我们从左到右扫描,找出当前这个圆的前驱,若他为上圆弧,则当前圆为其儿子,否则为其兄弟。这样我们就将圆变为了一个树形图,其中深度为奇数的贡献为正,否则为负。
代码如下:
注意:!!!!
- 如果set重载小于号的时候,不定义完全,会WA。
我就错了几遍 - T一定要为当前的x,不然会WA。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <set>
#define INF 2139062143
#define MAX 0x7ffffffffffffff
#define del(a,b) memset(a,b,sizeof(a))
#define Rint register int
using namespace std;
typedef long long ll;
template<typename T>
inline void read(T&x)
{
x=0;T k=1;char c=getchar();
while(!isdigit(c)){if(c=='-')k=-1;c=getchar();}
while(isdigit(c)){x=x*10+c-'0';c=getchar();}x*=k;
}
const int maxn=200000+5;
double T;
struct cir{
double x,y,r;
cir(double x=0.0,double y=0.0,double r=0.0):x(x),y(y),r(r){}
double h(int k){
return y + k*sqrt( r*r - (T-x)*(T-x) );
}
}c[maxn];
struct pic{
int num,k,deg;
pic(int num=0,int k=0,int deg=0):num(num),k(k),deg(deg){}
}p[maxn<<1];
bool operator < (const pic& a,const pic& b){
double y1=c[a.num].h(a.k),y2=c[b.num].h(b.k);
if(y1!=y2) return y1<y2;
return a.k<b.k;
}
bool cmp(pic a,pic b){
double x1=c[a.num].x-a.k*c[a.num].r;
double x2=c[b.num].x-b.k*c[b.num].r;
return x1<x2;
}
set<pic> s;
int n;
int main()
{
// freopen("4561.in","r",stdin);
// freopen("4561.out","w",stdout);
read(n);
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf",&c[i].x,&c[i].y,&c[i].r);
p[i*2-1]=pic(i,1);
p[i*2]=pic(i,-1);
}
sort(p+1,p+1+2*n,cmp);
set<pic>:: iterator it;
ll ans=0;
int deg;
for(int i=1;i<=2*n;i++){
T=c[p[i].num].x-p[i].k*c[p[i].num].r;//当前的扫描线位置
if(p[i].k==1){
it=s.upper_bound(p[i]);
if(it==s.end()) deg=1;
else{
if(it->k==1) deg=it->deg+1;
else deg=it->deg;
}
if(deg&1) ans+=ll(c[p[i].num].r*c[p[i].num].r);
else ans-=ll(c[p[i].num].r*c[p[i].num].r);
s.insert(pic(p[i].num,1,deg));
s.insert(pic(p[i].num,-1,deg));
}
else{
s.erase(pic(p[i].num,1,deg));
s.erase(pic(p[i].num,-1,deg));
}
}
printf("%lld",ans);
return 0;
}