同样在问题中引入扫描线和事件的思想
每一个矩形对应两个事件 $(y_1, x_1, x_2, 1), (y_2, x_1, x_2, -1)$
分别表示矩形边界的插入和删除
首先将矩形的 xx 坐标离散化,$[x_1, x_2]$离散化成 $[xl, xr)$
对于事件 $(y_1, x_1, x_2, 1)$
实际上在线段树 $[xl, xr)$ 执行区间加,下边界就 $+1$,上边界 $-1$
同时注意,因为有离散化操作,所以在线段树中,需要维护 $[xl, xr)$ 区间原来的长度
可以在线段树初始化操作的时候,对于离散化之后的坐标 $x$ 执行单点修改
假设 $x$ 对应原来的坐标是 rm[x]
,那么 set(x, len = rm[x+1] - rm[x])
接下来考虑统计答案,对于每一个事件,应该要先统计,再修改(因为上边界要统计完再删除)
对于每一个事件,$ans += cover \cdot (y - py)$,其中 py
是上一个 y
坐标
cover
是扫描线中被覆盖的长度,直接统计比较难
可以考虑有多少长度未被覆盖,未被覆盖的长度就是节点的 val = 0
线段树可以维护最小值出现的次数 mincnt
,也就是 0
出现的次数
而一整段的长度就是根节点的 len
,这样被覆盖的长度就可以用
cover = root.len - root.mincnt
来表示
#include <bits/stdc++.h>
using namespace std;
// segtree
namespace internal {
// @param n `0 <= n`
// @return minimum non-negative `x` s.t. `n <= 2**x`
int ceil_pow2(int n) {
int x = 0;
while ((1U << x) < (unsigned int)(n)) x++;
return x;
}
// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
// constexpr int bsf_constexpr(unsigned int n) {
// int x = 0;
// while (!(n & (1 << x))) x++;
// return x;
// }
// @param n `1 <= n`
// @return minimum non-negative `x` s.t. `(n & (1 << x)) != 0`
int bsf(unsigned int n) {
#ifdef _MSC_VER
unsigned long index;
_BitScanForward(&index, n);
return index;
#else
return __builtin_ctz(n);
#endif
}
} // namespace internal
// segtree
namespace Seg {
template <class S,
S (*op)(S, S),
S (*e)(),
class F,
S (*mapping)(F, S),
F (*composition)(F, F),
F (*id)()>
struct lazy_segtree {
public:
lazy_segtree() : lazy_segtree(0) {}
explicit lazy_segtree(int n) : lazy_segtree(std::vector<S>(n, e())) {}
explicit lazy_segtree(const std::vector<S>& v) : _n(int(v.size())) {
log = internal::ceil_pow2(_n);
size = 1 << log;
d = std::vector<S>(2 * size, e());
lz = std::vector<F>(size, id());
for (int i = 0; i < _n; i++) d[size + i] = v[i];
for (int i = size - 1; i >= 1; i--) {
update(i);
}
}
void set(int p, S x) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
d[p] = x;
for (int i = 1; i <= log; i++) update(p >> i);
}
S get(int p) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
return d[p];
}
S prod(int l, int r) {
assert(0 <= l && l <= r && r <= _n);
if (l == r) return e();
l += size;
r += size;
for (int i = log; i >= 1; i--) {
if (((l >> i) << i) != l) push(l >> i);
if (((r >> i) << i) != r) push((r - 1) >> i);
}
S sml = e(), smr = e();
while (l < r) {
if (l & 1) sml = op(sml, d[l++]);
if (r & 1) smr = op(d[--r], smr);
l >>= 1;
r >>= 1;
}
return op(sml, smr);
}
S all_prod() { return d[1]; }
void apply(int p, F f) {
assert(0 <= p && p < _n);
p += size;
for (int i = log; i >= 1; i--) push(p >> i);
d[p] = mapping(f, d[p]);
for (int i = 1; i <= log; i++) update(p >> i);
}
void apply(int l, int r, F f) {
assert(0 <= l && l <= r && r <= _n);
if (l == r) return;
l += size;
r += size;
for (int i = log; i >= 1; i--) {
if (((l >> i) << i) != l) push(l >> i);
if (((r >> i) << i) != r) push((r - 1) >> i);
}
{
int l2 = l, r2 = r;
while (l < r) {
if (l & 1) all_apply(l++, f);
if (r & 1) all_apply(--r, f);
l >>= 1;
r >>= 1;
}
l = l2;
r = r2;
}
for (int i = 1; i <= log; i++) {
if (((l >> i) << i) != l) update(l >> i);
if (((r >> i) << i) != r) update((r - 1) >> i);
}
}
template <bool (*g)(S)> int max_right(int l) {
return max_right(l, [](S x) { return g(x); });
}
template <class G> int max_right(int l, G g) {
assert(0 <= l && l <= _n);
assert(g(e()));
if (l == _n) return _n;
l += size;
for (int i = log; i >= 1; i--) push(l >> i);
S sm = e();
do {
while (l % 2 == 0) l >>= 1;
if (!g(op(sm, d[l]))) {
while (l < size) {
push(l);
l = (2 * l);
if (g(op(sm, d[l]))) {
sm = op(sm, d[l]);
l++;
}
}
return l - size;
}
sm = op(sm, d[l]);
l++;
} while ((l & -l) != l);
return _n;
}
template <bool (*g)(S)> int min_left(int r) {
return min_left(r, [](S x) { return g(x); });
}
template <class G> int min_left(int r, G g) {
assert(0 <= r && r <= _n);
assert(g(e()));
if (r == 0) return 0;
r += size;
for (int i = log; i >= 1; i--) push((r - 1) >> i);
S sm = e();
do {
r--;
while (r > 1 && (r % 2)) r >>= 1;
if (!g(op(d[r], sm))) {
while (r < size) {
push(r);
r = (2 * r + 1);
if (g(op(d[r], sm))) {
sm = op(d[r], sm);
r--;
}
}
return r + 1 - size;
}
sm = op(d[r], sm);
} while ((r & -r) != r);
return 0;
}
private:
int _n, size, log;
std::vector<S> d;
std::vector<F> lz;
void update(int k) { d[k] = op(d[2 * k], d[2 * k + 1]); }
void all_apply(int k, F f) {
d[k] = mapping(f, d[k]);
if (k < size) lz[k] = composition(f, lz[k]);
}
void push(int k) {
all_apply(2 * k, lz[k]);
all_apply(2 * k + 1, lz[k]);
lz[k] = id();
}
};
} // namespace Seg
// ============================================================== //
using namespace Seg;
const double eps = 1e-6;
int dcmp(double x) {
if (fabs(x) < eps) return 0;
return x < 0 ? -1 : 1;
}
struct S {
double minv;
double mincnt;
double len;
};
S op(S a, S b) {
S res;
res.minv = (dcmp(a.minv-b.minv) < 0 ? a.minv : b.minv);
if (dcmp(a.minv-b.minv) < 0) res.mincnt = a.mincnt;
else if (dcmp(a.minv-b.minv) > 0) res.mincnt = b.mincnt;
else res.mincnt = a.mincnt + b.mincnt;
res.len = a.len + b.len;
return res;
}
S e() {
return S{0, 0, 0};
}
// F long long
S mapping(double f, S x) {
S res;
res.minv = x.minv + f;
res.mincnt = x.mincnt;
res.len = x.len;
return res;
}
double composition(double f, double g) {
return f + g;
}
double id() {
return 0.0;
}
typedef array<double, 4> Arr;
int n;
double solve(int n) {
// freopen("input.txt", "r", stdin);
vector<Arr> event;
vector<double> vx;
for (int i = 0; i < n; i++) {
double x1, x2, y1, y2;
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
vx.push_back(x1), vx.push_back(x2);
event.push_back({y1, x1, x2, 1.0});
event.push_back({y2, x1, x2, -1.0});
}
sort(event.begin(), event.end());
sort(vx.begin(), vx.end(), [](double a, double b) {
return dcmp(a-b) < 0;
});
vx.erase(unique(vx.begin(), vx.end(), [](double a, double b) {
return dcmp(a-b) == 0;
}), vx.end());
int m = vx.size() - 1;
lazy_segtree<S, op, e, double, mapping, composition, id> tr(m);
for (int i = 0; i <= m - 1; i++) {
double len = fabs(vx[i] - vx[i+1]);
tr.set(i, S{0, len, len});
}
double totlen = tr.all_prod().mincnt;
// printf("%.3lf\n", totlen);
double ans = 0;
double py = 0;
for (const auto &evt : event) {
double cover = totlen;
if (dcmp(tr.all_prod().minv) == 0) {
cover -= tr.all_prod().mincnt;
}
ans += cover * (evt[0] - py);
int _x1 = lower_bound(vx.begin(), vx.end(), evt[1]) - vx.begin();
int _x2 = lower_bound(vx.begin(), vx.end(), evt[2]) - vx.begin();
if (_x1 < _x2) {
tr.apply(_x1, _x2, evt[3]);
}
py = evt[0];
}
return ans;
}
int main() {
//freopen("input.txt", "r", stdin);
int cas = 0;
while (scanf("%d", &n) != EOF && n) {
printf("Test case #%d\n", ++cas);
double ans = solve(n);
printf("Total explored area: %.2lf\n", ans);
printf("\n");
}
}