列表

详情


NC20148. [JLOI2016]圆的异或并

描述

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

输入描述

第一行包含一个正整数N,代表圆的个数。
接下来N行,每行3个非负整数x,y,r,表示一个圆心在(x,y),半径为r的圆。
保证|x|,|y|, ≤ 10^8,r > 0,N ≤ 200000

输出描述

仅一行一个整数,表示所有圆的异或面积并除以圆周率Pi的结果。

示例1

输入:

2 
0 0 1 
0 0 2

输出:

3

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 330ms, 内存消耗: 23104K, 提交时间: 2022-11-29 15:28:42

#include<iostream>
#include<cstring>
#include<set>
#include<cmath>
#include<algorithm>
using namespace std;
using LL = long long;
const int maxn = 2e5 + 5;
const double eps = 1e-8;
struct Op{
    int pos, x, y, r, id, type;
}op[maxn * 2];
int sign[maxn];

int nowx;

inline LL sqr(int x){
    return 1LL * x * x;
}

struct Node{
    int x, y, r, op, id;
    double inter() const{
        if (op) return y + sqrt(sqr(r) - sqr(x - nowx)) + eps;
        return y - sqrt(sqr(r) - sqr(x - nowx));
    }

    bool operator<(const Node &t) const{
        return inter() < t.inter();
    }
};

int main(){

#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    int n;
    cin >> n;
    int cnt = 0;
    for(int i = 1; i <= n; i++){
        int x, y, r;
        cin >> x >> y >> r;
        op[++cnt] = {x - r, x, y, r, i, 0};
        op[++cnt] = {x + r, x, y, r, i, 1};
    }
    sort(op + 1, op + cnt + 1, [&](Op &a, Op &b){
        return a.pos < b.pos;
    });
    LL ans = 0;
    set<Node> s;
    for(int i = 1; i <= cnt; i++){
        auto [pos, x, y, r, id, type] = op[i];
        nowx = pos;
        if (type == 0){
            auto it = s.insert({x, y, r, 1, id}).first;
            if (it == s.begin()){
                sign[id] = 1;
            }
            else{
                if (prev(it)->op) sign[id] = sign[prev(it)->id];
                else sign[id] = sign[prev(it)->id] ^ 1;
            }
            s.insert({x, y, r, 0, id});
            if (sign[id]) ans += 1LL * r * r;
            else ans -= 1LL * r * r;
        }
        else{
            s.erase({x, y, r, 1, id});
            s.erase({x, y, r, 0, id});
        }
    }
    cout << ans << '\n';

}

C++ 解法, 执行用时: 531ms, 内存消耗: 28572K, 提交时间: 2022-06-29 16:40:06

#include<iostream>
#include<cstdio>
#include<set>
#include<algorithm>
#include<cmath>
#define N 200010
using namespace std;
long long T;
struct circle{long long x,y,r;};
struct ppp{long long num,x,o;}b[N<<1];
bool cmp(ppp x,ppp y){return x.x<y.x;}
circle c[N];
long long sqr(long long x){return x*x;}
bool operator <(ppp x,ppp y)
{
	double xx=c[x.num].y+x.o*sqrt(sqr(c[x.num].r)-sqr(T-c[x.num].x));
	double yy=c[y.num].y+y.o*sqrt(sqr(c[y.num].r)-sqr(T-c[y.num].x));
	if(xx!=yy) return xx<yy;
	return x.o<y.o;
}
set<ppp>S;
long long f[N];
int main()
{
	long long n;
	scanf("%lld",&n);
	long long i,j;
	for(i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld",&c[i].x,&c[i].y,&c[i].r);
		b[2*i-1]=(ppp){i,c[i].x-c[i].r,1};
		b[2*i]=(ppp){i,c[i].x+c[i].r,-1};
	}
	sort(b+1,b+2*n+1,cmp);
	set<ppp>::iterator it;
	for(i=1;i<=2*n;i++)
	{
		T=b[i].x;
		if(b[i].o==1)
		{
			it=S.upper_bound((ppp){b[i].num,0,-1});
			if(it==S.end()) f[b[i].num]=1;
			else
			{
				if((*it).o==1) f[b[i].num]=-f[(*it).num];
				else f[b[i].num]=f[(*it).num];
			}
			S.insert((ppp){b[i].num,0,-1});
			S.insert((ppp){b[i].num,0,1});
		}
		else
		{
			S.erase((ppp){b[i].num,0,-1});
			S.erase((ppp){b[i].num,0,1});
		}
	}
	long long ans=0;
	for(i=1;i<=n;i++)
	ans+=sqr(c[i].r)*f[i];
	printf("%lld",ans);
}

上一题