Skip to main content

atcoder/lib/data_structure/
dual_segment_tree.rs

1//! 区間更新・一点取得を行う双対セグメント木です。
2
3/// 半開区間への作用と一点取得を扱う双対セグメント木です。
4///
5/// 添字は 0-indexed、区間は `[left, right)` です。`compose(old, new)` は古い作用の後に
6/// 新しい作用を適用した合成を返し、結合則と単位元 `identity` を満たす必要があります。
7/// 作用が非可換でも、この順序を守れば扱えます。更新と取得はいずれも `O(log N)` です。
8///
9/// # Examples
10///
11/// ```
12/// use atcoder::data_structure::dual_segment_tree::DualSegmentTree;
13///
14/// let mut tree = DualSegmentTree::new(|a, b| a + b, 4, 0);
15/// tree.apply(1, 4, 3);
16/// tree.apply(2, 3, 2);
17/// assert_eq!(tree.get(2), 5);
18/// ```
19#[derive(Clone)]
20pub struct DualSegmentTree<T, F> {
21    compose: F,
22    identity: T,
23    len: usize,
24    size: usize,
25    log: usize,
26    data: Vec<T>,
27}
28
29impl<T: Copy, F: Fn(T, T) -> T> DualSegmentTree<T, F> {
30    /// 長さ `len`、各点の初期値が `identity` の木を作ります。計算量・メモリ量は `O(N)` です。
31    ///
32    /// `compose(old, new)` は、点に蓄積済みの作用 `old` の後に新しい作用 `new` を
33    /// 適用した合成を返す関数です。`identity` はこの関数の単位元である必要があります。
34    pub fn new(compose: F, len: usize, identity: T) -> Self {
35        Self::from_vec(vec![identity; len], compose, identity)
36    }
37
38    /// 各点の初期値を指定して木を構築します。計算量・メモリ量は `O(N)` です。
39    ///
40    /// `values[i]` が添字 `i` の初期値になります。`compose` と `identity` の条件は
41    /// [`new`](Self::new) と同じです。
42    pub fn from_vec(values: impl Into<Vec<T>>, compose: F, identity: T) -> Self {
43        let values = values.into();
44        let len = values.len();
45        let size = len.next_power_of_two().max(1);
46        let log = size.trailing_zeros() as usize;
47        let mut data = vec![identity; size * 2];
48        data[size..size + len].copy_from_slice(&values);
49        Self {
50            compose,
51            identity,
52            len,
53            size,
54            log,
55            data,
56        }
57    }
58
59    /// [`from_vec`](Self::from_vec) と同じです。各点の初期値を `values` で指定します。
60    pub fn from(compose: F, values: Vec<T>, identity: T) -> Self {
61        Self::from_vec(values, compose, identity)
62    }
63
64    fn apply_node(&mut self, index: usize, value: T) {
65        self.data[index] = (self.compose)(self.data[index], value);
66    }
67
68    fn push(&mut self, index: usize) {
69        let value = self.data[index];
70        self.apply_node(index << 1, value);
71        self.apply_node(index << 1 | 1, value);
72        self.data[index] = self.identity;
73    }
74
75    fn push_path(&mut self, index: usize) {
76        let index = index + self.size;
77        for height in (1..=self.log).rev() {
78            self.push(index >> height);
79        }
80    }
81
82    /// 半開区間 `[left, right)` の各点に `value` を適用します。
83    ///
84    /// 添字は 0 始まりです。範囲が `0..=len` を外れる、または `left > right` の場合は
85    /// panic します。空区間なら何もしません。各点では既存の作用の後に `value` を適用します。
86    /// 計算量は `O(log N)` です。
87    pub fn apply(&mut self, left: usize, right: usize, value: T) {
88        assert!(left <= right && right <= self.len, "range out of bounds");
89        if left == right {
90            return;
91        }
92        self.push_path(left);
93        self.push_path(right - 1);
94        let mut left = left + self.size;
95        let mut right = right + self.size;
96        while left < right {
97            if left & 1 == 1 {
98                self.apply_node(left, value);
99                left += 1;
100            }
101            if right & 1 == 1 {
102                right -= 1;
103                self.apply_node(right, value);
104            }
105            left >>= 1;
106            right >>= 1;
107        }
108    }
109
110    /// `index` 番目の値を返します。添字は 0 始まりで、`index >= len` なら panic します。
111    /// 蓄積された作用を古いものから新しいものの順に合成します。計算量は `O(log N)` です。
112    pub fn get(&self, index: usize) -> T {
113        assert!(index < self.len, "index out of bounds");
114        let mut index = index + self.size;
115        let mut path = Vec::with_capacity(self.log + 1);
116        while index > 0 {
117            path.push(index);
118            index >>= 1;
119        }
120        path.into_iter().fold(self.identity, |value, index| {
121            (self.compose)(value, self.data[index])
122        })
123    }
124
125    /// `index` 番目の値を返します。添字は 0 始まりです。
126    ///
127    /// [`get`](Self::get) と同じで、`index >= len` なら panic します。計算量は `O(log N)` です。
128    pub fn at(&self, index: usize) -> T {
129        self.get(index)
130    }
131}
132
133/// 矩形更新・一点取得を行う2次元双対セグメント木です。
134///
135/// 行区間 `[upper, lower)` と列区間 `[left, right)` はともに 0-indexed の半開区間です。
136/// `compose` は結合的な演算で、`identity` はその単位元である必要があります。また、
137/// 2 次元の更新ノードを走査する順序に依存しないよう、演算は可換である必要があります。
138/// 更新・取得は `O(log H log W)`、メモリは `O(HW)` です。
139#[derive(Clone)]
140pub struct DualSegmentTree2D<T, F> {
141    compose: F,
142    identity: T,
143    height: usize,
144    width: usize,
145    row_size: usize,
146    column_size: usize,
147    data: Vec<T>,
148}
149
150impl<T: Copy, F: Fn(T, T) -> T> DualSegmentTree2D<T, F> {
151    /// `height × width` の木を作り、すべての点の初期値を `identity` にします。
152    /// 添字は行・列とも 0 始まりです。`compose` は結合的かつ可換で、`identity` を
153    /// 単位元とする必要があります。メモリ量は `O(HW)` です。
154    pub fn new(height: usize, width: usize, compose: F, identity: T) -> Self {
155        let row_size = height.next_power_of_two().max(1);
156        let column_size = width.next_power_of_two().max(1);
157        Self {
158            compose,
159            identity,
160            height,
161            width,
162            row_size,
163            column_size,
164            data: vec![identity; 4 * row_size * column_size],
165        }
166    }
167
168    fn id(&self, row: usize, column: usize) -> usize {
169        row * (2 * self.column_size) + column
170    }
171
172    fn range_nodes(mut left: usize, mut right: usize, size: usize) -> Vec<usize> {
173        left += size;
174        right += size;
175        let mut nodes = Vec::new();
176        while left < right {
177            if left & 1 == 1 {
178                nodes.push(left);
179                left += 1;
180            }
181            if right & 1 == 1 {
182                right -= 1;
183                nodes.push(right);
184            }
185            left >>= 1;
186            right >>= 1;
187        }
188        nodes
189    }
190
191    /// 矩形 `[upper, lower) × [left, right)` の各点に `value` を適用します。
192    ///
193    /// 行・列区間は 0 始まりの半開区間です。各区間が対応する次元の範囲内でない場合や、
194    /// 左端が右端を超える場合は panic します。空の行区間または列区間なら何もしません。
195    /// 計算量は `O(log H log W)` です。
196    pub fn apply(&mut self, upper: usize, lower: usize, left: usize, right: usize, value: T) {
197        assert!(
198            upper <= lower && lower <= self.height,
199            "row range out of bounds"
200        );
201        assert!(
202            left <= right && right <= self.width,
203            "column range out of bounds"
204        );
205        for row in Self::range_nodes(upper, lower, self.row_size) {
206            for column in Self::range_nodes(left, right, self.column_size) {
207                let index = self.id(row, column);
208                self.data[index] = (self.compose)(self.data[index], value);
209            }
210        }
211    }
212
213    /// 点 `(row, column)` の値を返します。行・列は 0 始まりで、範囲外なら panic します。
214    /// 計算量は `O(log H log W)` です。
215    pub fn get(&self, row: usize, column: usize) -> T {
216        assert!(
217            row < self.height && column < self.width,
218            "index out of bounds"
219        );
220        let mut rows = Vec::new();
221        let mut row = row + self.row_size;
222        while row > 0 {
223            rows.push(row);
224            row >>= 1;
225        }
226        let mut columns = Vec::new();
227        let mut column = column + self.column_size;
228        while column > 0 {
229            columns.push(column);
230            column >>= 1;
231        }
232        let mut result = self.identity;
233        for row in rows {
234            for &column in &columns {
235                result = (self.compose)(result, self.data[self.id(row, column)]);
236            }
237        }
238        result
239    }
240
241    /// 点 `(row, column)` の値を返します。行・列は 0 始まりです。
242    ///
243    /// [`get`](Self::get) と同じで、範囲外なら panic します。計算量は `O(log H log W)` です。
244    pub fn at(&self, row: usize, column: usize) -> T {
245        self.get(row, column)
246    }
247}
248
249#[cfg(test)]
250mod tests {
251    use super::{DualSegmentTree, DualSegmentTree2D};
252
253    #[test]
254    fn applies_ranges() {
255        let mut tree = DualSegmentTree::new(|a, b| a + b, 4, 0);
256        tree.apply(0, 3, 2);
257        tree.apply(1, 4, 5);
258        assert_eq!([tree.get(0), tree.get(1), tree.get(3)], [2, 7, 5]);
259    }
260
261    #[test]
262    fn preserves_non_commutative_order() {
263        let compose = |old: (i64, i64), new: (i64, i64)| (new.0 * old.0, new.0 * old.1 + new.1);
264        let mut tree = DualSegmentTree::new(compose, 2, (1, 0));
265        tree.apply(0, 1, (2, 0));
266        tree.apply(0, 2, (1, 3));
267        assert_eq!(tree.get(0), (2, 3));
268    }
269
270    #[test]
271    fn applies_rectangles() {
272        let mut tree = DualSegmentTree2D::new(2, 3, |a, b| a + b, 0);
273        tree.apply(0, 2, 1, 3, 4);
274        assert_eq!(tree.get(1, 2), 4);
275        assert_eq!(tree.get(0, 0), 0);
276    }
277}