pub struct StaticSearch<K> {
storage: StaticSearchStorage,
len: usize,
marker: PhantomData<fn() -> K>,
}Expand description
A static search index over sorted integer or integer-encoded keys.
The index adds build time and storage. For a small number of searches, search the sorted slice directly instead.
Fields§
§storage: StaticSearchStorage§len: usize§marker: PhantomData<fn() -> K>Implementations§
Source§impl<K: SimdKey> StaticSearch<K>
impl<K: SimdKey> StaticSearch<K>
Sourcepub fn from_sorted(values: &[K]) -> Self
pub fn from_sorted(values: &[K]) -> Self
Builds an index over sorted values.
§Panics
Panics if values is not sorted or SimdKey does not satisfy its contract.
Examples found in repository?
9pub fn rectangle_sum(reader: impl Read, writer: impl Write) {
10 prepare_io!(buffered; reader, writer);
11 sc!(n, q, mut xyw: [(u32, u32, i64); n], queries: [(u32, u32, u32, u32); q]);
12 xyw.radix_sort_by_key(|&(x, ..)| x);
13 let xs: Vec<_> = xyw.iter().map(|&(x, ..)| x).collect();
14 let search = StaticSearch::from_sorted(&xs);
15 let endpoints: Vec<_> = queries.iter().flat_map(|&(l, _, r, _)| [l, r]).collect();
16 let mut positions = vec![0; endpoints.len()];
17 search.lower_bound_batch(&endpoints, &mut positions);
18 let ys = xyw.iter().map(|&(_, y, _)| y).collect();
19 let weights: Vec<_> = xyw.iter().map(|&(_, _, w)| w).collect();
20 let wm = WaveletMatrix::new(ys);
21 let fold = wm.build_fold::<AdditiveOperation<i64>>(&weights);
22 let result = fold.fold_lessthan_batch(
23 queries
24 .into_iter()
25 .zip(positions.as_chunks::<2>().0)
26 .flat_map(|((_, d, _, u), &[l, r])| [(d, l..r), (u, l..r)]),
27 );
28 for &[lower, upper] in result.as_chunks::<2>().0 {
29 pp!(upper - lower);
30 }
31}More examples
18pub fn point_set_range_composite_large_array(reader: impl Read, writer: impl Write) {
19 prepare_io!(buffered; reader, writer);
20 sc!(_n: u32, q, queries: [Query; q]);
21 let mut values: Vec<_> = queries
22 .iter()
23 .filter_map(|&query| match query {
24 Query::Set { p, .. } => Some(p),
25 _ => None,
26 })
27 .collect();
28 values.radix_sort_by_key(|&x| x);
29 values.dedup();
30 let search = StaticSearch::from_sorted(&values);
31 let mut seg = SegmentTree::<LinearOperation<M>>::new(values.len());
32 let mut endpoints = Vec::with_capacity(2 * q);
33 for &query in &queries {
34 match query {
35 Query::Set { p, .. } => endpoints.push(p),
36 Query::Apply { l, r, .. } => endpoints.extend([l, r]),
37 }
38 }
39 let mut positions = vec![0; endpoints.len()];
40 search.lower_bound_batch(&endpoints, &mut positions);
41 let mut positions = positions.into_iter();
42 for query in queries {
43 match query {
44 Query::Set { cd, .. } => seg.set(positions.next().unwrap(), cd),
45 Query::Apply { x, .. } => {
46 let l = positions.next().unwrap();
47 let r = positions.next().unwrap();
48 let (a, b) = seg.fold(l..r);
49 pp!(a * x + b);
50 }
51 }
52 }
53}18pub fn range_affine_range_sum_large_array(reader: impl Read, writer: impl Write) {
19 prepare_io!(reader, writer);
20 sc!(n: u32, q, queries: [Query; q]);
21 let mut values: Vec<_> = [0, n]
22 .into_iter()
23 .chain(queries.iter().flat_map(|&query| {
24 let (Query::Update { l, r, .. } | Query::Fold { l, r }) = query;
25 [l, r]
26 }))
27 .collect();
28 values.radix_sort_by_key(|&x| x);
29 values.dedup();
30 let search = StaticSearch::from_sorted(&values);
31 let mut seg = LazySegmentTree::<RangeSumRangeLinear<M>>::from_vec(
32 values
33 .windows(2)
34 .map(|w| (M::zero(), M::from(w[1] - w[0])))
35 .collect(),
36 );
37 let endpoints: Vec<_> = queries
38 .iter()
39 .flat_map(|&query| {
40 let (Query::Update { l, r, .. } | Query::Fold { l, r }) = query;
41 [l, r]
42 })
43 .collect();
44 let mut positions = vec![0; endpoints.len()];
45 search.lower_bound_batch(&endpoints, &mut positions);
46 for (query, &[l, r]) in queries.into_iter().zip(positions.as_chunks::<2>().0) {
47 match query {
48 Query::Update { bc, .. } => {
49 seg.update(l..r, bc);
50 }
51 Query::Fold { .. } => {
52 pp!(seg.fold(l..r).0);
53 }
54 }
55 }
56}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}8pub fn ordered_set(reader: impl Read, writer: impl Write) {
9 prepare_io!(buffered; reader, writer);
10 sc!(n, q, a: [u32; n], queries: [(u8, u32); q]);
11 let mut values: Vec<_> = a
12 .iter()
13 .copied()
14 .chain(queries.iter().filter_map(|&(t, x)| (t <= 1).then_some(x)))
15 .collect();
16 values.radix_sort_by_key(|&x| x);
17 values.dedup();
18 let search = StaticSearch::from_sorted(&values);
19 let endpoints: Vec<_> = a
20 .into_iter()
21 .chain(
22 queries
23 .iter()
24 .map(|&(t, x)| if t == 3 || t == 4 { x + 1 } else { x }),
25 )
26 .collect();
27 let mut positions = vec![0; endpoints.len()];
28 search.lower_bound_batch(&endpoints, &mut positions);
29 let mut counts = vec![0; values.len()];
30 for &k in &positions[..n] {
31 counts[k] = 1;
32 }
33 let mut seg = DaryPrefixSumTreeU32::from_slice(&counts);
34 for ((t, x), &k) in queries.into_iter().zip(&positions[n..]) {
35 match t {
36 0 => seg.set(k, 1),
37 1 => seg.set(k, 0),
38 2 => {
39 let k = seg.partition_point_acc(x - 1);
40 pp!(values.get(k).map_or(-1, |&x| x as i64));
41 }
42 3 => {
43 pp!(seg.accumulate0(k));
44 }
45 4 => {
46 let count = seg.accumulate0(k);
47 pp!(if count == 0 {
48 -1
49 } else {
50 values[seg.partition_point_acc(count - 1)] as i64
51 });
52 }
53 5 => {
54 let count = seg.accumulate0(k);
55 let k = seg.partition_point_acc(count);
56 pp!(values.get(k).map_or(-1, |&x| x as i64));
57 }
58 _ => unreachable!(),
59 }
60 }
61}10pub fn static_rectangle_add_rectangle_sum(reader: impl Read, writer: impl Write) {
11 prepare_io!(buffered; reader, writer);
12 sc!(n, q, rectangles: [(u32, u32, u32, u32, M); n], queries: [(u32, u32, u32, u32); q]);
13 let mut ys: Vec<_> = rectangles
14 .iter()
15 .flat_map(|&(_, d, _, u, _)| [d, u])
16 .collect();
17 ys.radix_sort_by_key(|&y| y);
18 ys.dedup();
19 let search = StaticSearch::from_sorted(&ys);
20 let endpoints: Vec<_> = rectangles
21 .iter()
22 .flat_map(|&(_, d, _, u, _)| [d, u])
23 .chain(queries.iter().flat_map(|&(_, d, _, u)| [d, u]))
24 .collect();
25 let mut positions = vec![0; endpoints.len()];
26 search.lower_bound_batch(&endpoints, &mut positions);
27 let mut points: Vec<_> = rectangles
28 .into_iter()
29 .zip(positions[..2 * n].as_chunks().0)
30 .flat_map(|((l, _, r, _, w), &[d, u])| {
31 let d = d as u32;
32 let u = u as u32;
33 [(l, d, w), (l, u, -w), (r, d, -w), (r, u, w)]
34 })
35 .collect();
36 points.radix_sort_by_key(|&(x, ..)| x);
37 let mut events: Vec<_> = queries
38 .into_iter()
39 .zip(positions[2 * n..].as_chunks().0)
40 .enumerate()
41 .flat_map(|(i, ((l, d, r, u), &[di, ui]))| {
42 let di = di as u32;
43 let ui = ui as u32;
44 [
45 (l, d, u, di, ui, i as u32, false),
46 (r, d, u, di, ui, i as u32, true),
47 ]
48 })
49 .collect();
50 events.radix_sort_by_key(|&(x, ..)| x);
51 let mut bit = BinaryIndexedTree::<ArrayOperation<AdditiveOperation<M>, 4>>::new(ys.len());
52 let mut points = points.into_iter().peekable();
53 let mut ans = vec![M::zero(); q];
54 for (x, d, u, di, ui, i, add) in events {
55 while points.peek().is_some_and(|&(px, ..)| px < x) {
56 let (px, py, w) = points.next().unwrap();
57 let wx = w * M::from(px);
58 let wy = w * M::from(ys[py as usize]);
59 bit.update(py as usize, [w, wx, wy, wx * M::from(ys[py as usize])]);
60 }
61 for (y, yi, add) in [(d, di, !add), (u, ui, add)] {
62 let [w, wx, wy, wxy] = bit.accumulate0(yi as usize);
63 let value = (w * M::from(x) - wx) * M::from(y) - wy * M::from(x) + wxy;
64 if add {
65 ans[i as usize] += value;
66 } else {
67 ans[i as usize] -= value;
68 }
69 }
70 }
71 pp!(@lf @it ans);
72}Sourcepub fn from_sorted_direct(values: &[K]) -> Self
pub fn from_sorted_direct(values: &[K]) -> Self
Builds a direct lookup table over sorted 8-bit or 16-bit values.
This layout uses a fixed table of 257 or 65,537 positions and is intended for query-heavy workloads.
§Panics
Panics if K::BITS is neither 8 nor 16, or if values is not sorted.
pub fn len(&self) -> usize
pub fn is_empty(&self) -> bool
Sourcepub fn lower_bound(&self, value: K) -> usize
pub fn lower_bound(&self, value: K) -> usize
Returns the first index whose value is greater than or equal to value.
Sourcepub fn upper_bound(&self, value: K) -> usize
pub fn upper_bound(&self, value: K) -> usize
Returns one past the last index whose value is less than or equal to value.
Sourcepub fn lower_bound_batch(&self, values: &[K], output: &mut [usize])
pub fn lower_bound_batch(&self, values: &[K], output: &mut [usize])
Writes the first index greater than or equal to each value into output.
§Panics
Panics if values and output have different lengths.
Examples found in repository?
9pub fn rectangle_sum(reader: impl Read, writer: impl Write) {
10 prepare_io!(buffered; reader, writer);
11 sc!(n, q, mut xyw: [(u32, u32, i64); n], queries: [(u32, u32, u32, u32); q]);
12 xyw.radix_sort_by_key(|&(x, ..)| x);
13 let xs: Vec<_> = xyw.iter().map(|&(x, ..)| x).collect();
14 let search = StaticSearch::from_sorted(&xs);
15 let endpoints: Vec<_> = queries.iter().flat_map(|&(l, _, r, _)| [l, r]).collect();
16 let mut positions = vec![0; endpoints.len()];
17 search.lower_bound_batch(&endpoints, &mut positions);
18 let ys = xyw.iter().map(|&(_, y, _)| y).collect();
19 let weights: Vec<_> = xyw.iter().map(|&(_, _, w)| w).collect();
20 let wm = WaveletMatrix::new(ys);
21 let fold = wm.build_fold::<AdditiveOperation<i64>>(&weights);
22 let result = fold.fold_lessthan_batch(
23 queries
24 .into_iter()
25 .zip(positions.as_chunks::<2>().0)
26 .flat_map(|((_, d, _, u), &[l, r])| [(d, l..r), (u, l..r)]),
27 );
28 for &[lower, upper] in result.as_chunks::<2>().0 {
29 pp!(upper - lower);
30 }
31}More examples
18pub fn point_set_range_composite_large_array(reader: impl Read, writer: impl Write) {
19 prepare_io!(buffered; reader, writer);
20 sc!(_n: u32, q, queries: [Query; q]);
21 let mut values: Vec<_> = queries
22 .iter()
23 .filter_map(|&query| match query {
24 Query::Set { p, .. } => Some(p),
25 _ => None,
26 })
27 .collect();
28 values.radix_sort_by_key(|&x| x);
29 values.dedup();
30 let search = StaticSearch::from_sorted(&values);
31 let mut seg = SegmentTree::<LinearOperation<M>>::new(values.len());
32 let mut endpoints = Vec::with_capacity(2 * q);
33 for &query in &queries {
34 match query {
35 Query::Set { p, .. } => endpoints.push(p),
36 Query::Apply { l, r, .. } => endpoints.extend([l, r]),
37 }
38 }
39 let mut positions = vec![0; endpoints.len()];
40 search.lower_bound_batch(&endpoints, &mut positions);
41 let mut positions = positions.into_iter();
42 for query in queries {
43 match query {
44 Query::Set { cd, .. } => seg.set(positions.next().unwrap(), cd),
45 Query::Apply { x, .. } => {
46 let l = positions.next().unwrap();
47 let r = positions.next().unwrap();
48 let (a, b) = seg.fold(l..r);
49 pp!(a * x + b);
50 }
51 }
52 }
53}18pub fn range_affine_range_sum_large_array(reader: impl Read, writer: impl Write) {
19 prepare_io!(reader, writer);
20 sc!(n: u32, q, queries: [Query; q]);
21 let mut values: Vec<_> = [0, n]
22 .into_iter()
23 .chain(queries.iter().flat_map(|&query| {
24 let (Query::Update { l, r, .. } | Query::Fold { l, r }) = query;
25 [l, r]
26 }))
27 .collect();
28 values.radix_sort_by_key(|&x| x);
29 values.dedup();
30 let search = StaticSearch::from_sorted(&values);
31 let mut seg = LazySegmentTree::<RangeSumRangeLinear<M>>::from_vec(
32 values
33 .windows(2)
34 .map(|w| (M::zero(), M::from(w[1] - w[0])))
35 .collect(),
36 );
37 let endpoints: Vec<_> = queries
38 .iter()
39 .flat_map(|&query| {
40 let (Query::Update { l, r, .. } | Query::Fold { l, r }) = query;
41 [l, r]
42 })
43 .collect();
44 let mut positions = vec![0; endpoints.len()];
45 search.lower_bound_batch(&endpoints, &mut positions);
46 for (query, &[l, r]) in queries.into_iter().zip(positions.as_chunks::<2>().0) {
47 match query {
48 Query::Update { bc, .. } => {
49 seg.update(l..r, bc);
50 }
51 Query::Fold { .. } => {
52 pp!(seg.fold(l..r).0);
53 }
54 }
55 }
56}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}8pub fn ordered_set(reader: impl Read, writer: impl Write) {
9 prepare_io!(buffered; reader, writer);
10 sc!(n, q, a: [u32; n], queries: [(u8, u32); q]);
11 let mut values: Vec<_> = a
12 .iter()
13 .copied()
14 .chain(queries.iter().filter_map(|&(t, x)| (t <= 1).then_some(x)))
15 .collect();
16 values.radix_sort_by_key(|&x| x);
17 values.dedup();
18 let search = StaticSearch::from_sorted(&values);
19 let endpoints: Vec<_> = a
20 .into_iter()
21 .chain(
22 queries
23 .iter()
24 .map(|&(t, x)| if t == 3 || t == 4 { x + 1 } else { x }),
25 )
26 .collect();
27 let mut positions = vec![0; endpoints.len()];
28 search.lower_bound_batch(&endpoints, &mut positions);
29 let mut counts = vec![0; values.len()];
30 for &k in &positions[..n] {
31 counts[k] = 1;
32 }
33 let mut seg = DaryPrefixSumTreeU32::from_slice(&counts);
34 for ((t, x), &k) in queries.into_iter().zip(&positions[n..]) {
35 match t {
36 0 => seg.set(k, 1),
37 1 => seg.set(k, 0),
38 2 => {
39 let k = seg.partition_point_acc(x - 1);
40 pp!(values.get(k).map_or(-1, |&x| x as i64));
41 }
42 3 => {
43 pp!(seg.accumulate0(k));
44 }
45 4 => {
46 let count = seg.accumulate0(k);
47 pp!(if count == 0 {
48 -1
49 } else {
50 values[seg.partition_point_acc(count - 1)] as i64
51 });
52 }
53 5 => {
54 let count = seg.accumulate0(k);
55 let k = seg.partition_point_acc(count);
56 pp!(values.get(k).map_or(-1, |&x| x as i64));
57 }
58 _ => unreachable!(),
59 }
60 }
61}10pub fn static_rectangle_add_rectangle_sum(reader: impl Read, writer: impl Write) {
11 prepare_io!(buffered; reader, writer);
12 sc!(n, q, rectangles: [(u32, u32, u32, u32, M); n], queries: [(u32, u32, u32, u32); q]);
13 let mut ys: Vec<_> = rectangles
14 .iter()
15 .flat_map(|&(_, d, _, u, _)| [d, u])
16 .collect();
17 ys.radix_sort_by_key(|&y| y);
18 ys.dedup();
19 let search = StaticSearch::from_sorted(&ys);
20 let endpoints: Vec<_> = rectangles
21 .iter()
22 .flat_map(|&(_, d, _, u, _)| [d, u])
23 .chain(queries.iter().flat_map(|&(_, d, _, u)| [d, u]))
24 .collect();
25 let mut positions = vec![0; endpoints.len()];
26 search.lower_bound_batch(&endpoints, &mut positions);
27 let mut points: Vec<_> = rectangles
28 .into_iter()
29 .zip(positions[..2 * n].as_chunks().0)
30 .flat_map(|((l, _, r, _, w), &[d, u])| {
31 let d = d as u32;
32 let u = u as u32;
33 [(l, d, w), (l, u, -w), (r, d, -w), (r, u, w)]
34 })
35 .collect();
36 points.radix_sort_by_key(|&(x, ..)| x);
37 let mut events: Vec<_> = queries
38 .into_iter()
39 .zip(positions[2 * n..].as_chunks().0)
40 .enumerate()
41 .flat_map(|(i, ((l, d, r, u), &[di, ui]))| {
42 let di = di as u32;
43 let ui = ui as u32;
44 [
45 (l, d, u, di, ui, i as u32, false),
46 (r, d, u, di, ui, i as u32, true),
47 ]
48 })
49 .collect();
50 events.radix_sort_by_key(|&(x, ..)| x);
51 let mut bit = BinaryIndexedTree::<ArrayOperation<AdditiveOperation<M>, 4>>::new(ys.len());
52 let mut points = points.into_iter().peekable();
53 let mut ans = vec![M::zero(); q];
54 for (x, d, u, di, ui, i, add) in events {
55 while points.peek().is_some_and(|&(px, ..)| px < x) {
56 let (px, py, w) = points.next().unwrap();
57 let wx = w * M::from(px);
58 let wy = w * M::from(ys[py as usize]);
59 bit.update(py as usize, [w, wx, wy, wx * M::from(ys[py as usize])]);
60 }
61 for (y, yi, add) in [(d, di, !add), (u, ui, add)] {
62 let [w, wx, wy, wxy] = bit.accumulate0(yi as usize);
63 let value = (w * M::from(x) - wx) * M::from(y) - wy * M::from(x) + wxy;
64 if add {
65 ans[i as usize] += value;
66 } else {
67 ans[i as usize] -= value;
68 }
69 }
70 }
71 pp!(@lf @it ans);
72}Sourcepub fn upper_bound_batch(&self, values: &[K], output: &mut [usize])
pub fn upper_bound_batch(&self, values: &[K], output: &mut [usize])
Writes one past the last index less than or equal to each value into output.
§Panics
Panics if values and output have different lengths.
pub fn range(&self, value: K) -> Range<usize> ⓘ
pub fn contains(&self, value: K) -> bool
Sourcefn build(values: &[K], backend: SimdBackend, direct: bool) -> Self
fn build(values: &[K], backend: SimdBackend, direct: bool) -> Self
Examples found in repository?
815 pub fn from_sorted(values: &[K]) -> Self {
816 Self::build(values, static_search_backend(K::BITS), false)
817 }
818
819 /// Builds a direct lookup table over sorted 8-bit or 16-bit `values`.
820 ///
821 /// This layout uses a fixed table of 257 or 65,537 positions and is intended
822 /// for query-heavy workloads.
823 ///
824 /// # Panics
825 ///
826 /// Panics if `K::BITS` is neither 8 nor 16, or if `values` is not sorted.
827 pub fn from_sorted_direct(values: &[K]) -> Self {
828 assert!(matches!(K::BITS, 8 | 16));
829 Self::build(values, static_search_backend(K::BITS), true)
830 }