library-rs

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub naoya675/library-rs

:heavy_check_mark: Suffix Array
(string/suffix-array/src/lib.rs)

Description

Verified with

Code

//! https://atcoder.github.io/ac-library/production/document_en/string.html

#[derive(Debug)]
pub struct SuffixArray;

impl SuffixArray {
    fn sa_naive<T: Copy + Ord + PartialOrd>(s: &Vec<T>) -> Vec<usize> {
        let n = s.len();
        let mut sa = (0..n).collect::<Vec<usize>>();
        sa.sort_by(|&a, &b| {
            if a == b {
                return std::cmp::Ordering::Greater;
            }
            let mut i = a;
            let mut j = b;
            while i < n && j < n {
                if s[i] != s[j] {
                    if s[i] < s[j] {
                        return std::cmp::Ordering::Less;
                    } else {
                        return std::cmp::Ordering::Greater;
                    }
                }
                i += 1;
                j += 1;
            }
            if a == n {
                std::cmp::Ordering::Less
            } else {
                std::cmp::Ordering::Greater
            }
        });
        sa
    }

    fn sa_doubling(s: &Vec<usize>) -> Vec<usize> {
        let n = s.len();
        let mut sa = (0..n).collect::<Vec<usize>>();
        let mut rank = s.clone();
        let mut rank_temp = vec![0; n];
        let mut k = 1;
        while k < n {
            let cmp = |&a: &usize, &b: &usize| {
                if rank[a] != rank[b] {
                    rank[a].cmp(&rank[b])
                } else {
                    let ra = if a + k < n { rank[a + k] as isize } else { -1 };
                    let rb = if b + k < n { rank[b + k] as isize } else { -1 };
                    if ra < rb {
                        std::cmp::Ordering::Less
                    } else {
                        std::cmp::Ordering::Greater
                    }
                }
            };
            sa.sort_by(cmp);
            rank_temp[sa[0]] = 0;
            for i in 1..n {
                rank_temp[sa[i]] = rank_temp[sa[i - 1]] + if cmp(&sa[i - 1], &sa[i]) == std::cmp::Ordering::Less { 1 } else { 0 };
            }
            std::mem::swap(&mut rank, &mut rank_temp);
            k <<= 1;
        }
        sa
    }

    fn sa_is(s: &Vec<usize>, upper: usize) -> Vec<usize> {
        let n = s.len();
        if n == 0 {
            return vec![];
        }
        if n == 1 {
            return vec![0];
        }
        if n == 2 {
            return if s[0] < s[1] { vec![0, 1] } else { vec![1, 0] };
        }

        let mut sa = vec![None; n];
        let mut ls = vec![0; n];
        for i in (0..n - 1).rev() {
            if s[i] == s[i + 1] {
                ls[i] = ls[i + 1];
            } else if s[i] < s[i + 1] {
                ls[i] = 1;
            } else if s[i] > s[i + 1] {
                ls[i] = 0;
            }
        }
        let mut sum_l = vec![0; upper + 1];
        let mut sum_s = vec![0; upper + 1];
        for i in 0..n {
            if ls[i] == 0 {
                sum_s[s[i]] += 1;
            } else {
                sum_l[s[i] + 1] += 1;
            }
        }
        for i in 0..upper + 1 {
            sum_s[i] += sum_l[i];
            if i < upper {
                sum_l[i + 1] += sum_s[i];
            }
        }

        let induce = |lms: &Vec<usize>, sa: &mut Vec<Option<usize>>| {
            sa.fill(None);
            let mut buf = sum_s.clone();
            for &d in lms {
                if d == n {
                    continue;
                }
                sa[buf[s[d]]] = Some(d);
                buf[s[d]] += 1;
            }
            let mut buf = sum_l.clone();
            sa[buf[s[n - 1]]] = Some(n - 1);
            buf[s[n - 1]] += 1;
            for i in 0..n {
                if let Some(v) = sa[i] {
                    if v >= 1 && ls[v - 1] == 0 {
                        sa[buf[s[v - 1]]] = Some(v - 1);
                        buf[s[v - 1]] += 1;
                    }
                }
            }
            let mut buf = sum_l.clone();
            for i in (0..n).rev() {
                if let Some(v) = sa[i] {
                    if v >= 1 && ls[v - 1] != 0 {
                        buf[s[v - 1] + 1] -= 1;
                        sa[buf[s[v - 1] + 1]] = Some(v - 1);
                    }
                }
            }
        };

        let mut lms_map = vec![None; n + 1];
        let mut m = 0;
        for i in 1..n {
            if ls[i - 1] == 0 && ls[i] != 0 {
                lms_map[i] = Some(m);
                m += 1;
            }
        }
        let mut lms = vec![];
        lms.reserve(m);
        for i in 1..n {
            if ls[i - 1] == 0 && ls[i] != 0 {
                lms.push(i);
            }
        }
        induce(&lms, &mut sa);
        if m > 0 {
            let mut sorted_lms = vec![];
            sorted_lms.reserve(m);
            for &v_option in &sa {
                if let Some(v) = v_option {
                    if lms_map[v].is_some() {
                        sorted_lms.push(v);
                    }
                }
            }
            let mut rec_s = vec![0; m];
            let mut rec_upper = 0;
            rec_s[lms_map[sorted_lms[0]].unwrap()] = 0;
            for i in 1..m {
                let mut l = sorted_lms[i - 1];
                let mut r = sorted_lms[i];
                let end_l = if lms_map[l].unwrap() + 1 < m { lms[lms_map[l].unwrap() + 1] } else { n };
                let end_r = if lms_map[r].unwrap() + 1 < m { lms[lms_map[r].unwrap() + 1] } else { n };
                let mut same = true;
                if end_l - l != end_r - r {
                    same = false;
                } else {
                    while l < end_l {
                        if s[l] != s[r] {
                            break;
                        }
                        l += 1;
                        r += 1;
                    }
                    if l == n || s[l] != s[r] {
                        same = false;
                    }
                }
                if !same {
                    rec_upper += 1;
                }
                rec_s[lms_map[sorted_lms[i]].unwrap()] = rec_upper;
            }
            let rec_sa = SuffixArray::sa_is(&rec_s, rec_upper);
            for i in 0..m {
                sorted_lms[i] = lms[rec_sa[i]];
            }
            induce(&sorted_lms, &mut sa);
        }
        sa.into_iter().map(|a| a.unwrap()).collect()
    }

    pub fn suffix_array<T: Copy + Ord + PartialOrd>(s: &Vec<T>) -> Vec<usize> {
        let n = s.len();
        let mut idx = (0..n).collect::<Vec<usize>>();
        idx.sort_by(|&a, &b| s[a].cmp(&s[b]));
        let mut t = vec![0; n];
        let mut now = 0;
        for i in 0..n {
            if i > 0 && s[idx[i - 1]] != s[idx[i]] {
                now += 1;
            }
            t[idx[i]] = now;
        }
        Self::sa_is(&t, now)
    }
}
Traceback (most recent call last):
  File "/opt/hostedtoolcache/Python/3.11.12/x64/lib/python3.11/site-packages/onlinejudge_verify/documentation/build.py", line 71, in _render_source_code_stat
    bundled_code = language.bundle(stat.path, basedir=basedir, options={'include_paths': [basedir]}).decode()
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.11.12/x64/lib/python3.11/site-packages/onlinejudge_verify/languages/rust.py", line 288, in bundle
    raise NotImplementedError
NotImplementedError
Back to top page