1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! 強連結成分分解。

/// lowlink に基づく強連結成分分解。
///
/// # Parameters
/// - `n`: 頂点数
/// - `vs`: 頂点集合
/// - `index`: 頂点から添字への番号づけをする関数
/// - `delta`: 頂点 `v` と関数 `search` を受け取る関数
///
/// `delta` は、`v` の各隣接頂点 `nv` に対して、`search(nv)`
/// を呼び出す必要がある。
///
/// # Return value
/// `index(v)` 番目の要素が `v` の属する強連結成分の番号である配列。
/// 番号づけはトポロジカル順に行われる。
///
/// # Examples
///
/// ```text
/// (0) ---> (1) ---> (3) ---> (5) ---> (6) ---> (7)
///  ^        |        |        ^        ^        |
///  |        v        v        |        |        |
/// (4) <--- (2)      (9)       +------ (8) <-----+
/// ```
///
/// ```
/// use nekolib::graph::scc;
///
/// let g = vec![
///     vec![1],
///     vec![2, 3],
///     vec![4],
///     vec![5, 9],
///     vec![0],
///     vec![6],
///     vec![7],
///     vec![8],
///     vec![5, 6],
///     vec![],
/// ];
/// let index = |&v: &usize| v;
/// let delta = |&v: &usize| g[v].iter().cloned();
/// let comp_id = scc(10, 0..10, index, delta);
///
/// assert_eq!(comp_id, vec![0, 0, 0, 1, 0, 3, 3, 3, 3, 2]);
/// ```
///
/// # Complexity
/// $O(|V|+|E|)$ 時間。
///
/// # References
/// - <https://niuez.github.io/posts/impl_abstract_dijkstra/>
pub fn scc<V, E>(
    n: usize,
    vs: impl Iterator<Item = V>,
    index: impl Fn(&V) -> usize + Copy,
    delta: impl Fn(&V) -> E + Copy,
) -> Vec<usize>
where
    E: Iterator<Item = V>,
{
    struct State {
        scc: Vec<Vec<usize>>,
        num: Vec<usize>,
        low: Vec<usize>,
        s: Vec<usize>,
        ins: Vec<bool>,
        t: usize,
    }

    fn dfs<V, E>(
        v: V,
        index: impl Fn(&V) -> usize + Copy,
        delta: impl Fn(&V) -> E + Copy,
        state: &mut State,
    ) where
        E: Iterator<Item = V>,
    {
        state.t += 1;
        let vi = index(&v);
        state.low[vi] = state.t;
        state.num[vi] = state.t;
        state.s.push(vi);
        state.ins[vi] = true;
        for nv in delta(&v) {
            let nvi = index(&nv);
            if state.num[nvi] == 0 {
                dfs(nv, index, delta, state);
                state.low[vi] = state.low[vi].min(state.low[nvi]);
            } else if state.ins[nvi] {
                state.low[vi] = state.low[vi].min(state.num[nvi]);
            }
        }
        if state.low[vi] == state.num[vi] {
            let mut tmp = vec![];
            loop {
                let nvi = state.s.pop().unwrap();
                state.ins[nvi] = false;
                tmp.push(nvi);
                if vi == nvi {
                    break;
                }
            }
            state.scc.push(tmp);
        }
    }

    let mut state = State {
        scc: vec![],
        num: vec![0; n],
        low: vec![0; n],
        s: vec![],
        ins: vec![false; n],
        t: 0,
    };

    for v in vs {
        if state.num[index(&v)] == 0 {
            dfs(v, index, delta, &mut state);
        }
    }

    let mut res = vec![0; n];
    for i in 0..state.scc.len() {
        for &c in &state.scc[i] {
            res[c] = state.scc.len() - i - 1;
        }
    }

    res
}