圆的异或并

bzoj 4561 圆的异或并

题意

在平面直角坐标系中给定\(N\)个圆。已知这些圆两两没有交点,即两圆的关系只存在相离和包含。求这些圆的异或面
积并。异或面积并为:当一片区域在奇数个圆内则计算其面积,当一片区域在偶数个圆内则不考虑。

解法

这个很简单

因为圆两两不相交,所以其相对位置不变,所以我们将其拆为两个半圆弧,当我们碰到左端点的时候,就加入这两个圆弧,碰到右端点的时候,就将他们删去。然后我们从左到右扫描,找出当前这个圆的前驱,若他为上圆弧,则当前圆为其儿子,否则为其兄弟。这样我们就将圆变为了一个树形图,其中深度为奇数的贡献为正,否则为负。

代码如下:

注意:!!!!

  1. 如果set重载小于号的时候,不定义完全,会WA。我就错了几遍
  2. 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;
}

posted @ 2018-08-21 08:40  Mr_asd  阅读(270)  评论(0编辑  收藏  举报