diff --git a/algo/avl_tree/src/lib.rs b/algo/avl_tree/src/lib.rs index 62805d7a..74ba97e8 100644 --- a/algo/avl_tree/src/lib.rs +++ b/algo/avl_tree/src/lib.rs @@ -1,3 +1,53 @@ +//! AVL木は高さバランスが保たれた自己平衡二分探索木です。 +//! +//! 各ノードにおいて左の子の高さと右の子の高さの差が1以下に保たれるため、 +//! 最悪計算量でもO(log n)での操作が保証されます。 +//! +//! ## 特徴 +//! +//! - **時間計算量**: 挿入、削除、検索、範囲クエリ全てO(log n) +//! - **空間計算量**: O(n) +//! - **順序統計**: k番目の要素の取得、要素の順位の取得が可能 +//! - **範囲クエリ**: 指定した値以下/以上の要素の検索が可能 +//! +//! ## 主な用途 +//! +//! - 動的な集合の管理で順序統計が必要な場合 +//! - lower_bound/upper_boundが頻繁に必要な場合 +//! - 要素の挿入・削除と同時に順位を管理したい場合 +//! - C++のstd::setのような機能が必要な場合 +//! +//! ## 基本的な使用例 +//! +//! ``` +//! use avl_tree::AvlTree; +//! +//! let mut tree = AvlTree::new(); +//! tree.insert(3); +//! tree.insert(1); +//! tree.insert(4); +//! tree.insert(1); // 重複は無視される +//! tree.insert(5); +//! +//! // 要素の存在確認 +//! assert!(tree.contains(&3)); +//! assert!(!tree.contains(&2)); +//! +//! // 順序統計: 0-indexedでk番目の要素を取得 +//! assert_eq!(tree.nth(0), Some(&1)); // 最小値 +//! assert_eq!(tree.nth(1), Some(&3)); +//! assert_eq!(tree.nth(2), Some(&4)); +//! assert_eq!(tree.nth(3), Some(&5)); // 最大値 +//! +//! // 範囲クエリ +//! assert_eq!(tree.le(&3), Some(&3)); // 3以下の最大値 +//! assert_eq!(tree.ge(&2), Some(&3)); // 2以上の最小値 +//! +//! // イテレータで昇順に取得 +//! let values: Vec<_> = tree.iter().collect(); +//! assert_eq!(values, vec![&1, &3, &4, &5]); +//! ``` + use std::{ cmp::{self, Ordering}, fmt, @@ -12,6 +62,10 @@ struct Node { size: usize, } +/// AVL木の実装です。 +/// +/// 自己平衡二分探索木の一種で、各ノードの左の子と右の子の高さの差を1以下に保つことで +/// 最悪時間計算量O(log n)を保証します。 #[derive(Clone)] pub struct AvlTree { n: usize, @@ -19,14 +73,46 @@ pub struct AvlTree { } impl AvlTree { + /// 新しい空のAVL木を作成します。 + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let tree: AvlTree = AvlTree::new(); + /// assert!(tree.is_empty()); + /// ``` pub fn new() -> Self { Self { n: 0, root: None } } + /// AVL木に含まれる要素数を返します。 + /// + /// 時間計算量: O(1) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// assert_eq!(tree.len(), 0); + /// tree.insert(42); + /// assert_eq!(tree.len(), 1); + /// ``` pub fn len(&self) -> usize { self.n } + /// AVL木が空かどうかを返します。 + /// + /// 時間計算量: O(1) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// assert!(tree.is_empty()); + /// tree.insert(1); + /// assert!(!tree.is_empty()); + /// ``` pub fn is_empty(&self) -> bool { self.n == 0 } @@ -140,6 +226,24 @@ impl AvlTree { node } + /// AVL木を昇順にソートされたVecに変換します。 + /// + /// この操作によってAVL木は空になります。 + /// + /// 時間計算量: O(n) + /// 空間計算量: O(n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(3); + /// tree.insert(1); + /// tree.insert(4); + /// + /// let vec = tree.into_sorted_vec(); + /// assert_eq!(vec, vec![1, 3, 4]); + /// ``` pub fn into_sorted_vec(mut self) -> Vec { fn collect(node: Option>>, acc: &mut Vec) { if let Some(node) = node { @@ -176,12 +280,35 @@ where last } - /// 集合にxが含まれるかを返す。 + /// 集合にxが含まれるかを返します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(42); + /// assert!(tree.contains(&42)); + /// assert!(!tree.contains(&24)); + /// ``` pub fn contains(&self, x: &T) -> bool { self.find_last(x).map_or(false, |node| x.eq(&node.x)) } - /// xを追加する。集合にxが含まれていなかった場合trueを返す。 + /// xを追加します。集合にxが含まれていなかった場合trueを返します。 + /// + /// 既に同じ値が存在する場合は何も行わずfalseを返します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// assert_eq!(tree.insert(42), true); // 新しい要素 + /// assert_eq!(tree.insert(42), false); // 既存の要素 + /// ``` pub fn insert(&mut self, x: T) -> bool { let root = self.root.take(); let mut inserted = false; @@ -222,7 +349,20 @@ where } } - /// xを削除する。集合にxが含まれていた場合trueを返す。 + /// xを削除します。集合にxが含まれていた場合trueを返します。 + /// + /// 要素が存在しない場合は何も行わずfalseを返します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(42); + /// assert_eq!(tree.remove(&42), true); // 存在する要素 + /// assert_eq!(tree.remove(&42), false); // 存在しない要素 + /// ``` pub fn remove(&mut self, x: &T) -> bool { let root = self.root.take(); let mut removed = false; @@ -287,7 +427,25 @@ where } } - /// x以下の最大の要素を返す + /// x以下の最大の要素を返します。 + /// + /// x以下の要素が存在しない場合はNoneを返します。 + /// これはC++のstd::setのlower_boundに相当します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(1); + /// tree.insert(3); + /// tree.insert(5); + /// + /// assert_eq!(tree.le(&3), Some(&3)); // ちょうど存在する + /// assert_eq!(tree.le(&4), Some(&3)); // 存在しないが、それ以下がある + /// assert_eq!(tree.le(&0), None); // それ以下が存在しない + /// ``` pub fn le(&self, x: &T) -> Option<&T> { let mut current = &self.root; let mut result = None; @@ -306,7 +464,25 @@ where result } - /// x以上の最小の要素を返す + /// x以上の最小の要素を返します。 + /// + /// x以上の要素が存在しない場合はNoneを返します。 + /// これはC++のstd::setのupper_boundに相当します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(1); + /// tree.insert(3); + /// tree.insert(5); + /// + /// assert_eq!(tree.ge(&3), Some(&3)); // ちょうど存在する + /// assert_eq!(tree.ge(&2), Some(&3)); // 存在しないが、それ以上がある + /// assert_eq!(tree.ge(&6), None); // それ以上が存在しない + /// ``` pub fn ge(&self, x: &T) -> Option<&T> { let mut current = &self.root; let mut result = None; @@ -325,7 +501,28 @@ where result } - /// 0-indexedでn番目の要素を返す + /// 0-indexedでn番目の要素を返します。 + /// + /// 昇順でソートしたときのn番目の要素を取得します。 + /// インデックスが範囲外の場合はNoneを返します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(10); + /// tree.insert(5); + /// tree.insert(15); + /// tree.insert(1); + /// + /// assert_eq!(tree.nth(0), Some(&1)); // 最小値 + /// assert_eq!(tree.nth(1), Some(&5)); + /// assert_eq!(tree.nth(2), Some(&10)); + /// assert_eq!(tree.nth(3), Some(&15)); // 最大値 + /// assert_eq!(tree.nth(4), None); // 範囲外 + /// ``` pub fn nth(&self, n: usize) -> Option<&T> { if n >= self.len() { return None; @@ -349,8 +546,26 @@ where unreachable!() } - /// xより小さい要素の個数を返す - /// 集合がxを含む場合Ok, xを含まない場合Err + /// xより小さい要素の個数を返します。 + /// + /// 集合がxを含む場合Ok(順位)、xを含まない場合Err(挿入位置)を返します。 + /// 順位は0-indexedです。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(1); + /// tree.insert(3); + /// tree.insert(5); + /// + /// assert_eq!(tree.position(&1), Ok(0)); // 1は0番目 + /// assert_eq!(tree.position(&3), Ok(1)); // 3は1番目 + /// assert_eq!(tree.position(&2), Err(1)); // 2は存在しないが1番目に挿入される + /// assert_eq!(tree.position(&6), Err(3)); // 6は存在しないが3番目に挿入される + /// ``` pub fn position(&self, x: &T) -> Result { let mut current = &self.root; let mut count = 0; @@ -393,6 +608,7 @@ where } } +/// AVL木の要素を昇順で走査するイテレータです。 pub struct Iter<'a, T> { stack: Vec<&'a Node>, } @@ -424,6 +640,21 @@ impl<'a, T> Iterator for Iter<'a, T> { } impl AvlTree { + /// AVL木の要素を昇順で走査するイテレータを返します。 + /// + /// 時間計算量: O(1)で開始、全体でO(n) + /// + /// # Examples + /// ``` + /// use avl_tree::AvlTree; + /// let mut tree = AvlTree::new(); + /// tree.insert(3); + /// tree.insert(1); + /// tree.insert(4); + /// + /// let values: Vec<_> = tree.iter().collect(); + /// assert_eq!(values, vec![&1, &3, &4]); + /// ``` pub fn iter(&self) -> Iter { Iter::new(&self.root) } diff --git a/algo/fenwick_tree/src/lib.rs b/algo/fenwick_tree/src/lib.rs index 84869b68..a6900ed3 100644 --- a/algo/fenwick_tree/src/lib.rs +++ b/algo/fenwick_tree/src/lib.rs @@ -1,6 +1,60 @@ +//! Fenwick Tree(Binary Indexed Tree, BIT)は一点更新と区間和クエリを効率的に行うデータ構造です。 +//! +//! セグメントツリーより実装が簡単で、特に区間和や区間XORなど群の演算に対して +//! 高速に動作します。 +//! +//! ## 特徴 +//! +//! - **時間計算量**: +//! - 一点更新: O(log n) +//! - 区間和クエリ: O(log n) +//! - 構築: O(n log n) (各要素を個別に追加する場合) +//! - **空間計算量**: O(n) +//! - **実装の簡潔さ**: セグメントツリーより短く書ける +//! - **制約**: 逆元が存在する演算(群)にのみ対応 +//! +//! ## 主な用途 +//! +//! - 区間和クエリ(Range Sum Query) +//! - 区間XORクエリ +//! - 配列の要素の増減操作 +//! - 転倒数の計算 +//! - 座標圧縮と組み合わせた集計処理 +//! +//! ## 基本的な使用例 +//! +//! ``` +//! use fenwick_tree::FenwickTree; +//! +//! let mut ft = FenwickTree::new(5, 0); +//! ft.add(0, 1); // インデックス0に1を加算 +//! ft.add(2, 10); // インデックス2に10を加算 +//! ft.add(4, 100); // インデックス4に100を加算 +//! // 配列: [1, 0, 10, 0, 100] +//! +//! assert_eq!(ft.sum(0..1), 1); // [0,1)の和: 1 +//! assert_eq!(ft.sum(0..3), 11); // [0,3)の和: 1 + 0 + 10 = 11 +//! assert_eq!(ft.sum(2..5), 110); // [2,5)の和: 10 + 0 + 100 = 110 +//! assert_eq!(ft.sum(..), 111); // 全体の和: 111 +//! +//! // 要素の増減 +//! ft.add(1, 5); // インデックス1に5を加算 +//! assert_eq!(ft.sum(0..3), 16); // 1 + 5 + 10 = 16 +//! +//! ft.add(2, -3); // インデックス2から3を減算 +//! assert_eq!(ft.sum(2..3), 7); // 10 - 3 = 7 +//! ``` +//! +//! ## 参考資料 +//! +//! - [Binary Indexed Tree のしくみ](http://hos.ac/slides/20140319_bit.pdf) + use std::ops::{Bound, RangeBounds}; -/// Fenwick Tree (Binary Indexed Tree) [http://hos.ac/slides/20140319_bit.pdf](http://hos.ac/slides/20140319_bit.pdf) +/// Fenwick Tree(Binary Indexed Tree)の実装です。 +/// +/// 一点更新と区間和クエリを効率的に行うことができます。 +/// 群の演算(逆元が存在する演算)に対応しています。 /// /// # Examples /// ``` @@ -30,6 +84,23 @@ where T: std::ops::AddAssign, T: std::ops::SubAssign, { + /// 長さ `n` のFenwick Treeを単位元 `e` で初期化します。 + /// + /// すべての要素が `e` で初期化されます。 + /// + /// 時間計算量: O(n) + /// 空間計算量: O(n) + /// + /// # Examples + /// ``` + /// use fenwick_tree::FenwickTree; + /// + /// // 整数の和用 + /// let ft_sum = FenwickTree::new(10, 0); + /// + /// // 浮動小数点の和用 + /// let ft_float = FenwickTree::new(10, 0.0); + /// ``` pub fn new(n: usize, e: T) -> Self { Self { n, @@ -37,8 +108,21 @@ where dat: vec![e; n + 1], } } - // 0-indexed - // a[k] += x + + /// インデックス `k` の要素に `x` を加算します。 + /// + /// 0-indexedで指定したインデックスの要素に値を加算します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use fenwick_tree::FenwickTree; + /// let mut ft = FenwickTree::new(5, 0); + /// ft.add(2, 10); // インデックス2に10を加算 + /// ft.add(2, 5); // インデックス2にさらに5を加算 + /// assert_eq!(ft.sum(2..3), 15); // インデックス2の値は15 + /// ``` pub fn add(&mut self, k: usize, x: T) { assert!(k < self.n); let mut k = k + 1; @@ -47,8 +131,10 @@ where k += 1 << k.trailing_zeros(); } } - // 1-indexed - // a[1] + a[2] + ... + a[r] + /// 1-indexedでの累積和を計算します(内部用)。 + /// + /// インデックス1からrまでの要素の和を返します。 + /// BITの内部実装で使用される関数です。 fn _sum(&self, r: usize) -> T { assert!(r <= self.n); let mut result = self.e; @@ -59,7 +145,27 @@ where } result } - // 0-indexed + /// 指定した範囲の要素の和を計算します。 + /// + /// 0-indexedで範囲を指定し、その範囲の要素の和を返します。 + /// 範囲指定にはRustの標準的な範囲記法が使用できます。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use fenwick_tree::FenwickTree; + /// let mut ft = FenwickTree::new(5, 0); + /// ft.add(1, 2); + /// ft.add(2, 3); + /// ft.add(3, 5); + /// + /// assert_eq!(ft.sum(1..4), 10); // インデックス[1,4)の和: 2 + 3 + 5 = 10 + /// assert_eq!(ft.sum(1..=3), 10); // インデックス[1,3]の和: 2 + 3 + 5 = 10 + /// assert_eq!(ft.sum(2..4), 8); // インデックス[2,4)の和: 3 + 5 = 8 + /// assert_eq!(ft.sum(..), 10); // 全体の和: 10 + /// assert_eq!(ft.sum(0..0), 0); // 空の範囲: 0(単位元) + /// ``` pub fn sum(&self, range: impl RangeBounds) -> T { let start = match range.start_bound() { Bound::Included(&start) => start, diff --git a/algo/segment_tree/src/lib.rs b/algo/segment_tree/src/lib.rs index 9fea6dc8..a981ebb0 100644 --- a/algo/segment_tree/src/lib.rs +++ b/algo/segment_tree/src/lib.rs @@ -1,9 +1,67 @@ +//! セグメントツリーは範囲クエリと一点更新を効率的に行うデータ構造です。 +//! +//! 任意の結合則を満たす二項演算(モノイド)に対して、 +//! 配列の区間に対する演算結果を高速に求めることができます。 +//! +//! ## 特徴 +//! +//! - **時間計算量**: +//! - 一点更新: O(log n) +//! - 範囲クエリ: O(log n) +//! - 構築: O(n) +//! - **空間計算量**: O(n) +//! - **汎用性**: 任意のモノイドに対応(和、積、最小値、最大値、GCD、LCMなど) +//! +//! ## 主な用途 +//! +//! - 区間和クエリ(Range Sum Query) +//! - 区間最小値/最大値クエリ(Range Minimum/Maximum Query) +//! - 区間GCD/LCMクエリ +//! - 二分探索との組み合わせ(max_right, min_left) +//! - 動的プログラミングの最適化 +//! +//! ## 実装上の注意 +//! +//! この実装は教育目的で作られており、実行時間が遅い場合があります。 +//! 時間制限の厳しい問題では[ACライブラリ](https://github.com/rust-lang-ja/ac-library-rs)の +//! セグメントツリーの使用を推奨します。 +//! +//! ## 基本的な使用例 +//! +//! ``` +//! use segment_tree::SegmentTree; +//! +//! // 区間和を求めるセグメントツリー +//! let mut seg = SegmentTree::new(5, 0, |a, b| a + b); +//! seg.set(0, 1); +//! seg.set(2, 10); +//! seg.set(4, 100); +//! // 配列: [1, 0, 10, 0, 100] +//! +//! assert_eq!(seg.fold(0..3), 11); // 区間[0,3)の和: 1 + 0 + 10 = 11 +//! assert_eq!(seg.fold(2..5), 110); // 区間[2,5)の和: 10 + 0 + 100 = 110 +//! assert_eq!(seg.fold(..), 111); // 全体の和: 111 +//! +//! // 区間最小値を求めるセグメントツリー +//! let mut min_seg = SegmentTree::new(4, i32::MAX, |a, b| (*a).min(*b)); +//! min_seg.set(0, 3); +//! min_seg.set(1, 1); +//! min_seg.set(2, 4); +//! min_seg.set(3, 2); +//! +//! assert_eq!(min_seg.fold(0..4), 1); // 全体の最小値 +//! assert_eq!(min_seg.fold(1..3), 1); // 区間[1,3)の最小値 +//! ``` + use std::fmt; use std::ops::{Bound, Index, RangeBounds}; -/// __注意⚠__ この実装は遅いので time limit の厳しい問題には代わりに ACL のセグメントツリーを使うこと。 +/// セグメントツリーの実装です。 +/// +/// モノイド(結合則を満たす二項演算と単位元を持つ代数構造)に対して +/// 範囲クエリと一点更新を効率的に行うことができます。 /// -/// セグメントツリーです。 +/// **注意⚠** この実装は遅いので time limit の厳しい問題には代わりに ACL のセグメントツリーを使うこと。 #[derive(Clone)] pub struct SegmentTree { original_n: usize, @@ -21,7 +79,25 @@ where { /// 長さ `n` の列を初期値 `e` で初期化します。 /// - /// `multiply` は fold に使う二項演算です。 + /// `multiply` は fold に使う二項演算です。この演算は結合則を満たす必要があります。 + /// `e` は `multiply` の単位元である必要があります。 + /// + /// 時間計算量: O(n) + /// 空間計算量: O(n) + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// + /// // 区間和クエリ用 + /// let seg_sum = SegmentTree::new(5, 0, |a, b| a + b); + /// + /// // 区間最小値クエリ用 + /// let seg_min = SegmentTree::new(5, i32::MAX, |a, b| (*a).min(*b)); + /// + /// // 区間最大値クエリ用 + /// let seg_max = SegmentTree::new(5, i32::MIN, |a, b| (*a).max(*b)); + /// ``` pub fn new(n: usize, e: T, multiply: F) -> Self { let original_n = n; let n = n.next_power_of_two(); @@ -35,17 +111,52 @@ where } /// 列の `i` 番目の要素を取得します。 + /// + /// 時間計算量: O(1) + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(3, 0, |a, b| a + b); + /// seg.set(1, 42); + /// assert_eq!(seg.get(1), &42); + /// assert_eq!(seg.get(0), &0); + /// ``` pub fn get(&self, i: usize) -> &T { assert!(i < self.original_n); &self.dat[i + self.n] } /// 列の `i` 番目の要素を `x` で更新します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(3, 0, |a, b| a + b); + /// seg.set(1, 42); + /// assert_eq!(seg.get(1), &42); + /// assert_eq!(seg.fold(..), 42); + /// ``` pub fn set(&mut self, i: usize, x: T) { self.update(i, |_| x); } - /// 列の `i` 番目の要素を `f` で更新します。 + /// 列の `i` 番目の要素を関数 `f` で更新します。 + /// + /// 現在の値に対して `f` を適用した結果で要素を更新します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(3, 0, |a, b| a + b); + /// seg.set(1, 10); + /// seg.update(1, |x| x + 5); // 10 + 5 = 15 + /// assert_eq!(seg.get(1), &15); + /// ``` pub fn update(&mut self, i: usize, f: U) where U: FnOnce(&T) -> T, @@ -59,7 +170,26 @@ where } } + /// 指定した範囲の要素に対して `multiply` 演算を適用した結果を返します。 + /// /// `range` が `l..r` として、`multiply(l番目の要素, multiply(..., multiply(r-2番目の要素, r-1番目の要素)))` の値を返します。 + /// 範囲が空の場合は単位元 `e` を返します。 + /// + /// 時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(5, 0, |a, b| a + b); + /// seg.set(1, 2); + /// seg.set(2, 3); + /// seg.set(3, 5); + /// + /// assert_eq!(seg.fold(1..4), 10); // 2 + 3 + 5 = 10 + /// assert_eq!(seg.fold(0..2), 2); // 0 + 2 = 2 + /// assert_eq!(seg.fold(2..2), 0); // 空の範囲は単位元 + /// assert_eq!(seg.fold(..), 10); // 全体の和 + /// ``` pub fn fold(&self, range: impl RangeBounds) -> T { let start = match range.start_bound() { Bound::Included(&start) => start, @@ -77,9 +207,30 @@ where /// `f(fold(l..r)) = true` となる最大の `r` を返します。 /// + /// 左端 `l` から始めて、条件 `f` を満たす最も長い区間の右端を求めます。 + /// 二分探索のような用途に使用できます。 + /// + /// 時間計算量: O(log n) + /// /// # Panics /// - /// if `f(e) = false` + /// `f(e) = false` の場合にパニックします。 + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(5, 0, |a, b| a + b); + /// seg.set(0, 3); + /// seg.set(1, 1); + /// seg.set(2, 4); + /// seg.set(3, 1); + /// seg.set(4, 5); + /// // 配列: [3, 1, 4, 1, 5] + /// + /// // 区間和が10以下となる最大の右端を求める + /// assert_eq!(seg.max_right(0, |&sum| sum <= 10), 4); // [0,4)の和は9 + /// assert_eq!(seg.max_right(1, |&sum| sum <= 5), 3); // [1,3)の和は5 + /// ``` pub fn max_right

(&self, l: usize, f: P) -> usize where P: Fn(&T) -> bool, @@ -126,9 +277,30 @@ where /// `f(fold(l..r)) = true` となる最小の `l` を返します。 /// + /// 右端 `r` から逆向きに、条件 `f` を満たす最も長い区間の左端を求めます。 + /// 二分探索のような用途に使用できます。 + /// + /// 時間計算量: O(log n) + /// /// # Panics /// - /// if `f(e) = false` + /// `f(e) = false` の場合にパニックします。 + /// + /// # Examples + /// ``` + /// use segment_tree::SegmentTree; + /// let mut seg = SegmentTree::new(5, 0, |a, b| a + b); + /// seg.set(0, 3); + /// seg.set(1, 1); + /// seg.set(2, 4); + /// seg.set(3, 1); + /// seg.set(4, 5); + /// // 配列: [3, 1, 4, 1, 5] + /// + /// // 区間和が10以下となる最小の左端を求める + /// assert_eq!(seg.min_left(5, |&sum| sum <= 10), 2); // [2,5)の和は10 + /// assert_eq!(seg.min_left(4, |&sum| sum <= 5), 2); // [2,4)の和は5 + /// ``` pub fn min_left

(&self, r: usize, f: P) -> usize where P: Fn(&T) -> bool, diff --git a/algo/treap/src/lib.rs b/algo/treap/src/lib.rs index 4bc1be7b..7a91629f 100644 --- a/algo/treap/src/lib.rs +++ b/algo/treap/src/lib.rs @@ -1,3 +1,55 @@ +//! Treapは木構造とヒープ性質を組み合わせたランダム化データ構造です。 +//! +//! 各ノードに値と優先度(priority)を持ち、値について二分探索木の性質を、 +//! 優先度についてヒープの性質を満たします。優先度をランダムに決めることで +//! 期待時間計算量O(log n)での操作を実現します。 +//! +//! ## 特徴 +//! +//! - **期待時間計算量**: 挿入、削除、検索、範囲クエリ全てO(log n) +//! - **空間計算量**: O(n) +//! - **順序統計**: k番目の要素の取得、要素の順位の取得が可能 +//! - **範囲クエリ**: 指定した値以下/以上の要素の検索が可能 +//! - **ランダム化**: 優先度をランダムに設定することで平衡を保つ +//! +//! ## 主な用途 +//! +//! - AVL木やRed-Black木より実装が簡単で同等の性能が欲しい場合 +//! - 動的な集合の管理で順序統計が必要な場合 +//! - lower_bound/upper_boundが頻繁に必要な場合 +//! - 実装の簡潔さを重視する競技プログラミング +//! +//! ## 基本的な使用例 +//! +//! ``` +//! use treap::Treap; +//! +//! let mut treap = Treap::default(); // デフォルトの乱数ジェネレータを使用 +//! treap.insert(3); +//! treap.insert(1); +//! treap.insert(4); +//! treap.insert(1); // 重複は無視される +//! treap.insert(5); +//! +//! // 要素の存在確認 +//! assert!(treap.contains(&3)); +//! assert!(!treap.contains(&2)); +//! +//! // 順序統計: 0-indexedでk番目の要素を取得 +//! assert_eq!(treap.nth(0), Some(&1)); // 最小値 +//! assert_eq!(treap.nth(1), Some(&3)); +//! assert_eq!(treap.nth(2), Some(&4)); +//! assert_eq!(treap.nth(3), Some(&5)); // 最大値 +//! +//! // 範囲クエリ +//! assert_eq!(treap.le(&3), Some(&3)); // 3以下の最大値 +//! assert_eq!(treap.ge(&2), Some(&3)); // 2以上の最小値 +//! +//! // イテレータで昇順に取得 +//! let values: Vec<_> = treap.iter().collect(); +//! assert_eq!(values, vec![&1, &3, &4, &5]); +//! ``` + use std::{ cmp::{self, Ordering}, fmt, @@ -14,6 +66,11 @@ struct Node { size: usize, } +/// Treapの実装です。 +/// +/// ランダム化二分探索木の一種で、値については二分探索木の性質を、 +/// 優先度についてはヒープの性質を満たします。 +/// ランダムな優先度により期待時間計算量O(log n)を実現します。 pub struct Treap { n: usize, root: Option>>, @@ -21,6 +78,18 @@ pub struct Treap { } impl Treap { + /// 指定した乱数ジェネレータで新しいTreapを作成します。 + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// use rand::rngs::StdRng; + /// use rand::SeedableRng; + /// + /// let rng = StdRng::seed_from_u64(42); + /// let treap: Treap = Treap::new(rng); + /// assert!(treap.is_empty()); + /// ``` pub fn new(rng: R) -> Self { Self { n: 0, @@ -29,10 +98,34 @@ impl Treap { } } + /// Treapに含まれる要素数を返します。 + /// + /// 時間計算量: O(1) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// assert_eq!(treap.len(), 0); + /// treap.insert(42); + /// assert_eq!(treap.len(), 1); + /// ``` pub fn len(&self) -> usize { self.n } + /// Treapが空かどうかを返します。 + /// + /// 時間計算量: O(1) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// assert!(treap.is_empty()); + /// treap.insert(1); + /// assert!(!treap.is_empty()); + /// ``` pub fn is_empty(&self) -> bool { self.n == 0 } @@ -93,6 +186,24 @@ impl Treap { node.as_ref().map_or(0, |n| n.size) } + /// Treapを昇順にソートされたVecに変換します。 + /// + /// この操作によってTreapは空になります。 + /// + /// 時間計算量: O(n) + /// 空間計算量: O(n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(3); + /// treap.insert(1); + /// treap.insert(4); + /// + /// let vec = treap.into_sorted_vec(); + /// assert_eq!(vec, vec![1, 3, 4]); + /// ``` pub fn into_sorted_vec(mut self) -> Vec { fn collect(node: Option>>, acc: &mut Vec) { if let Some(node) = node { @@ -138,12 +249,36 @@ where last } - /// 集合にxが含まれるかを返す。 + /// 集合にxが含まれるかを返します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(42); + /// assert!(treap.contains(&42)); + /// assert!(!treap.contains(&24)); + /// ``` pub fn contains(&self, x: &T) -> bool { self.find_last(x).map_or(false, |node| x.eq(&node.x)) } - /// xを削除する。集合にxが含まれていた場合trueを返す。 + /// xを削除します。集合にxが含まれていた場合trueを返します。 + /// + /// 要素が存在しない場合は何も行わずfalseを返します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(42); + /// assert_eq!(treap.remove(&42), true); // 存在する要素 + /// assert_eq!(treap.remove(&42), false); // 存在しない要素 + /// ``` pub fn remove(&mut self, x: &T) -> bool { let root = self.root.take(); let mut removed = false; @@ -208,7 +343,25 @@ where } } - /// x以下の最大の要素を返す + /// x以下の最大の要素を返します。 + /// + /// x以下の要素が存在しない場合はNoneを返します。 + /// これはC++のstd::setのlower_boundに相当します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(1); + /// treap.insert(3); + /// treap.insert(5); + /// + /// assert_eq!(treap.le(&3), Some(&3)); // ちょうど存在する + /// assert_eq!(treap.le(&4), Some(&3)); // 存在しないが、それ以下がある + /// assert_eq!(treap.le(&0), None); // それ以下が存在しない + /// ``` pub fn le(&self, x: &T) -> Option<&T> { let mut current = &self.root; let mut result = None; @@ -227,7 +380,25 @@ where result } - /// x以上の最小の要素を返す + /// x以上の最小の要素を返します。 + /// + /// x以上の要素が存在しない場合はNoneを返します。 + /// これはC++のstd::setのupper_boundに相当します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(1); + /// treap.insert(3); + /// treap.insert(5); + /// + /// assert_eq!(treap.ge(&3), Some(&3)); // ちょうど存在する + /// assert_eq!(treap.ge(&2), Some(&3)); // 存在しないが、それ以上がある + /// assert_eq!(treap.ge(&6), None); // それ以上が存在しない + /// ``` pub fn ge(&self, x: &T) -> Option<&T> { let mut current = &self.root; let mut result = None; @@ -246,7 +417,28 @@ where result } - /// 0-indexedでn番目の要素を返す + /// 0-indexedでn番目の要素を返します。 + /// + /// 昇順でソートしたときのn番目の要素を取得します。 + /// インデックスが範囲外の場合はNoneを返します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(10); + /// treap.insert(5); + /// treap.insert(15); + /// treap.insert(1); + /// + /// assert_eq!(treap.nth(0), Some(&1)); // 最小値 + /// assert_eq!(treap.nth(1), Some(&5)); + /// assert_eq!(treap.nth(2), Some(&10)); + /// assert_eq!(treap.nth(3), Some(&15)); // 最大値 + /// assert_eq!(treap.nth(4), None); // 範囲外 + /// ``` pub fn nth(&self, n: usize) -> Option<&T> { if n >= self.len() { return None; @@ -270,8 +462,26 @@ where unreachable!() } - /// xより小さい要素の個数を返す - /// 集合がxを含む場合Ok, xを含まない場合Err + /// xより小さい要素の個数を返します。 + /// + /// 集合がxを含む場合Ok(順位)、xを含まない場合Err(挿入位置)を返します。 + /// 順位は0-indexedです。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(1); + /// treap.insert(3); + /// treap.insert(5); + /// + /// assert_eq!(treap.position(&1), Ok(0)); // 1は0番目 + /// assert_eq!(treap.position(&3), Ok(1)); // 3は1番目 + /// assert_eq!(treap.position(&2), Err(1)); // 2は存在しないが1番目に挿入される + /// assert_eq!(treap.position(&6), Err(3)); // 6は存在しないが3番目に挿入される + /// ``` pub fn position(&self, x: &T) -> Result { let mut current = &self.root; let mut count = 0; @@ -304,7 +514,19 @@ where T: cmp::Ord, R: RngCore, { - /// xを追加する。集合にxが含まれていなかった場合trueを返す。 + /// xを追加します。集合にxが含まれていなかった場合trueを返します。 + /// + /// 既に同じ値が存在する場合は何も行わずfalseを返します。 + /// + /// 期待時間計算量: O(log n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// assert_eq!(treap.insert(42), true); // 新しい要素 + /// assert_eq!(treap.insert(42), false); // 既存の要素 + /// ``` pub fn insert(&mut self, x: T) -> bool { let root = self.root.take(); let mut inserted = false; @@ -376,6 +598,7 @@ where } } +/// Treapの要素を昇順で走査するイテレータです。 pub struct Iter<'a, T> { stack: Vec<&'a Node>, _phantom: PhantomData<&'a T>, @@ -411,6 +634,21 @@ impl<'a, T> Iterator for Iter<'a, T> { } impl Treap { + /// Treapの要素を昇順で走査するイテレータを返します。 + /// + /// 期待時間計算量: O(1)で開始、全体でO(n) + /// + /// # Examples + /// ``` + /// use treap::Treap; + /// let mut treap = Treap::default(); + /// treap.insert(3); + /// treap.insert(1); + /// treap.insert(4); + /// + /// let values: Vec<_> = treap.iter().collect(); + /// assert_eq!(values, vec![&1, &3, &4]); + /// ``` pub fn iter(&self) -> Iter { Iter::new(&self.root) }