[JLOI2016]圆的异或并
Problem
平面上给定若干互不相交的圆(仅有包含和相离两种关系),求圆的异或面积(覆盖奇数次的区域贡献答案)除以 \(\pi\)。
\(n\leq 2\times 10^5,|x_i|,|y_i|\leq 10^8\)
Sol & Code
扫描线从左往右扫。由于圆和圆之间不相交,与扫描线交点位置关系不变(上半圆看成左括号,下半圆看成右括号,将会一直满足括号序列合法)。然后加入一个圆就维护下新加进来的两个括号。使用 set
维护。复杂度 \(\mathcal O(n\log n)\)。
#include <bits/stdc++.h>
#define pb push_back
using std::vector; using std::set; using std::sort;
typedef long long LL;
typedef double DB;
const int N = 200005;
const DB eps = 1e-7;
int n, x[N], y[N], r[N], tag[N];
struct node1 { int pos, id; };
vector<node1> v;
bool cmp(node1 a, node1 b) { return a.pos < b.pos; }
int X;
LL sqr(int x) { return 1LL * x * x; }
struct node2 {
int id, ty;
DB calc() { return y[id] + (ty == 1 ? 1 : -1) * sqrt(sqr(r[id]) - sqr(X - x[id]) + eps); }
friend bool operator < (node2 a, node2 b) { return a.calc() < b.calc() - eps; }
};
set<node2> s;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &x[i], &y[i], &r[i]);
v.pb((node1){x[i] - r[i], i}), v.pb((node1){x[i] + r[i], -i});
}
sort(v.begin(), v.end(), cmp);
for (int i = 0; i < v.size(); i++) {
X = v[i].pos;
if (v[i].id > 0) {
set<node2>::iterator it = s.insert((node2){v[i].id, 1}).first;
if (it != s.begin()) {
--it;
if (it->ty == -1) tag[v[i].id] = tag[it->id] ^ 1;
else tag[v[i].id] = tag[it->id];
} else tag[v[i].id] = 1;
s.insert((node2){v[i].id, -1});
} else
s.erase((node2){-v[i].id, 1}), s.erase((node2){-v[i].id, -1});
}
LL ans = 0;
for (int i = 1; i <= n; i++) ans += (tag[i] ? 1 : -1) * sqr(r[i]);
printf("%lld", ans);
return 0;
}