码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4561:圆的异或并(扫描线+set||splay||线段树)

时间:2018-03-22 19:25:42      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:scan   pac   其他   fine   pre   ios   alt   圆心   color   

在平面直角坐标系中给定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

 

思路:扫描线,有很多这样的题,思路就是分成上下两半圆,然后用数据结构。

具体:把一个圆分为上下两个半圆,然后每次扫描线扫到一个圆,去找这个圆“上面第一个半圆”,是上半圆的话,则被包含,否则不。

排序是根据直线与圆的交点的纵坐标排序得到:

            下面左图,B上面第一个圆是A,因为3上面第一个点是2。而2代表下半圆,说明无圆包含B。

            下图右图,B上面第一个圆是A,因为3上面第一个点是1。而1代表上半圆,说明第一个包含B的是A。(也右可能A还被其他圆包含)

简单证明划分圆来解决的可行性:

            由于圆之间不相交,所以我们用平行Y轴是直线去扫描的时候(从左向右),直线与圆产生一些交点,

           易得:一个圆与直线的交点相邻,即这个交点“属于哪个圆”这个属性“相离”或者“包含”,不会“交叉”。

技术分享图片

             如左图:A圆与直线交点1,2,B圆与直线交点3,4。二圆相离,所以(1,2),(3,4)。

             如右图:A圆与直线交点1,2,B圆与直线交点3,4。二圆包含。所以(1,(3,4)2)。

             不会出现1,3,24

             因此,我们只需要找上面第一个圆即可,这个圆是在直线上交点的上面第一个。

 

 

数据结构用于查找大于等于某值的数,可以是set,线段树,判平衡树等。

这里是练习平衡树,但是为了保险,先写了好写的set。

 

待续。。。。

#include<set>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long 
const int maxn=200010;
struct cir{
     ll x,y,r;
     cir(){}
     cir(ll xx,ll yy,ll rr):x(xx),y(yy),r(rr){}
}c[maxn];
struct ins{
     int x,opt,id;
     ins(){}
     ins(int xx,int oo,int ii):x(xx),opt(oo),id(ii){}
}w[maxn<<1];=
ll Lx,sig[maxn];  set<ins>s;
ll cal(ll x) { return x*x; }
bool cmp(ins a,ins b){ return a.x<b.x; }
bool operator <(ins a,ins b){
    
    double y1=c[a.id].y+a.opt*sqrt(cal(c[a.id].r)-cal(c[a.id].x-Lx));
    double y2=c[b.id].y+b.opt*sqrt(cal(c[b.id].r)-cal(c[b.id].x-Lx));
    if(y1==y2) return a.opt<b.opt; //当一个圆的左顶点刚好在LX线上? 
    return y1<y2; 
}
int main()
{
    int N; scanf("%d",&N);
    for(int i=1;i<=N;i++){
        scanf("%lld%lld%lld",&c[i].x,&c[i].y,&c[i].r);
        w[(i<<1)-1]=ins(c[i].x-c[i].r,1,i);
        w[i<<1]=ins(c[i].x+c[i].r,-1,i);
    }
    sort(w+1,w+(N<<1)+1,cmp);
    for(int i=1;i<=(N<<1);i++){
        Lx=w[i].x; 
        if(w[i].opt==1){//左,加圆 
            
            set<ins>::iterator it;
            it=s.upper_bound(ins(0,1,w[i].id));
            if(it==s.end()) sig[w[i].id]=1;
            else{
                if((*it).opt==-1) sig[w[i].id]=sig[(*it).id];
                else sig[w[i].id]=-sig[(*it).id];
            }
            s.insert(ins(0,1,w[i].id));
            s.insert(ins(0,-1,w[i].id));
        }
        else {
            s.erase(ins(0,1,w[i].id));
            s.erase(ins(0,-1,w[i].id));
        }
    }
    ll ans=0;
    for(int i=1;i<=N;i++)  ans+=sig[i]*cal(c[i].r);
    printf("%lld\n",ans); 
    return 0;
}

 

BZOJ4561:圆的异或并(扫描线+set||splay||线段树)

标签:scan   pac   其他   fine   pre   ios   alt   圆心   color   

原文地址:https://www.cnblogs.com/hua-dong/p/8625278.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!