library_checker/data_structure/
area_of_union_of_rectangles.rs1use competitive::prelude::*;
2use competitive::{
3 algebra::RangeMinCountRangeAdd,
4 algorithm::SliceSortExt,
5 data_structure::{LazySegmentTree, StaticSearch},
6};
7
8#[verify::library_checker("area_of_union_of_rectangles")]
9pub fn area_of_union_of_rectangles(reader: impl Read, writer: impl Write) {
10 prepare_io!(buffered; reader, writer);
11 sc!(n, rectangles: [(u32, u32, u32, u32); n]);
12 let endpoints: Vec<_> = rectangles.iter().flat_map(|&(_, d, _, u)| [d, u]).collect();
13 let mut ys = endpoints.clone();
14 ys.radix_sort_by_key(|&y| y);
15 ys.dedup();
16 let search = StaticSearch::from_sorted(&ys);
17 let mut positions = vec![0; endpoints.len()];
18 search.lower_bound_batch(&endpoints, &mut positions);
19 let mut events: Vec<_> = rectangles
20 .into_iter()
21 .zip(positions.as_chunks().0)
22 .flat_map(|((l, _, r, _), &[d, u])| {
23 let d = d as u32;
24 let u = u as u32;
25 [(l, d, u, 1), (r, d, u, -1)]
26 })
27 .collect();
28 events.radix_sort_by_key(|&(x, ..)| x);
29 let mut seg = LazySegmentTree::<RangeMinCountRangeAdd<i32>>::from_vec(
30 ys.windows(2).map(|w| (0, (w[1] - w[0]) as usize)).collect(),
31 );
32 let height = (ys[ys.len() - 1] - ys[0]) as usize;
33 let mut prev_x = 0;
34 let mut area = 0u64;
35 for (x, d, u, delta) in events {
36 let (minimum, count) = seg.fold_all();
37 let covered = height - if minimum == 0 { count } else { 0 };
38 area += (x - prev_x) as u64 * covered as u64;
39 seg.update(d as usize..u as usize, delta);
40 prev_x = x;
41 }
42 pp!(area);
43}