zoukankan      html  css  js  c++  java
  • 圆的异或并

    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;
    }
    
    
  • 相关阅读:
    第四节 哈希类型
    第三节 string类型
    第二节 redis的数据类型和一些通用的键命令
    第一节 Redis的安装配置
    第三十二节 定时器
    第三十一节 sed命令
    第三十节 awk命令
    第二十九节 cut命令
    第二十八节 函数和脚本调试
    Gartner 如何看 RASP 和 WAF?
  • 原文地址:https://www.cnblogs.com/mrasd/p/9509279.html
Copyright © 2011-2022 走看看