competitive/algorithm/
mo_algorithm.rs1#[macro_export]
30macro_rules! mo_algorithm {
31 (
32 $lr:expr,
33 ($l:ident, $r:ident),
34 |$i:tt| $inc:expr,
35 |$d:tt| $dec:expr,
36 |$a:tt| $answer:expr $(,)?
37 ) => {{
38 $crate::mo_algorithm!(
39 $lr,
40 ($l, $r),
41 |$i| $inc,
42 |$d| $dec,
43 |$d| $dec,
44 |$i| $inc,
45 |$a| $answer
46 );
47 }};
48 (
49 $lr:expr,
50 ($l:ident, $r:ident),
51 |$il:tt| $incl:expr,
52 |$dl:tt| $decl:expr,
53 |$ir:tt| $incr:expr,
54 |$dr:tt| $decr:expr,
55 |$a:tt| $answer:expr $(,)?
56 ) => {{
57 fn hilbert_curve_order(mut x: usize, mut y: usize, m: usize) -> usize {
58 let n = 1usize << m;
59 let mut ord = 0usize;
60 for k in (0..m).rev() {
61 let rx = x >> k & 1;
62 let ry = y >> k & 1;
63 ord += (1 << k * 2) * (3 * rx ^ ry);
64 if ry == 0 {
65 if rx == 1 {
66 x = n - x - 1;
67 y = n - y - 1;
68 }
69 ::std::mem::swap(&mut x, &mut y);
70 }
71 }
72 ord
73 }
74 let lr: &[(usize, usize)] = $lr;
75 let q = lr.len();
76 let maxv = lr.iter().map(|&(l, r)| l.max(r)).max().unwrap_or_default();
77 let mut m = 0usize;
78 while maxv >= 1 << m {
79 m += 1;
80 }
81 let mut idx: Vec<usize> = (0..q).collect();
82 let ord: Vec<_> = lr
83 .iter()
84 .map(|&(l, r)| hilbert_curve_order(l, r, m))
85 .collect();
86 idx.sort_unstable_by_key(|&i| ord[i]);
87 let (mut $l, mut $r) = (0usize, 0usize);
88 for &$a in idx.iter() {
89 let (nl, nr) = lr[$a];
90 while $l > nl {
91 $l -= 1;
92 let $dl: usize = $l;
93 $decl;
94 }
95 while $r < nr {
96 let $ir: usize = $r;
97 $incr;
98 $r += 1;
99 }
100 while $l < nl {
101 let $il: usize = $l;
102 $incl;
103 $l += 1;
104 }
105 while $r > nr {
106 $r -= 1;
107 let $dr: usize = $r;
108 $decr;
109 }
110 $answer;
111 }
112 }};
113}
114
115#[cfg(test)]
116mod tests {
117 use crate::{rand, tools::NotEmptySegment as Nes, tools::Xorshift};
118
119 #[test]
120 fn test_mo_algorithm() {
121 let mut rng = Xorshift::default();
122 for _ in 0..50 {
123 rand!(rng, n: 1..50, q: 1..100, a: [1i64..1000; n], lr: [Nes(n); q]);
124 let mut ans = 0;
125 let mut acc = 0;
126 mo_algorithm!(
127 &lr,
128 (l, r),
129 |i| acc -= a[i],
130 |i| acc += a[i],
131 |i| acc += a[i],
132 |i| acc -= a[i],
133 |i| ans += acc
134 );
135 let mut exp = 0;
136 for (l, r) in lr {
137 exp += a[l..r].iter().sum::<i64>();
138 }
139 assert_eq!(ans, exp);
140 }
141 }
142}