Problem:
Score : 100 points

Problem Statement

You are given a string of length N. Calculate the number of distinct substrings of S.

Constraints

1 \leq N \leq 500,000

S consists of lowercase English letters.

Input

Input is given from Standard Input in the following format:

S

Output

Print the answer.

Sample Input 1

abcbcba

Sample Output 1

21

Sample Input 2

mississippi

Sample Output 2

53

Sample Input 3

ababacaca

Sample Output 3

33

Sample Input 4

aaaaa

Sample Output 4

5

Solution in Ruby (2.7.1) (judge verdict: Accepted)

def sa_naive(s)
    n = s.size
    (0...n).to_a.sort! do |l, r|
        x = nil
        while l < n && r < n
            break x = s[l] <=> s[r] if s[l] != s[r]
            l += 1
            r += 1
        end
        x or l == n ? -1 : 1
    end
end

def sa_doubling(s)
    n = s.size
    sa = (0...n).to_a
    rnk = s.map(&:ord)
    tmp = Array.new(n)
    k = 1

    cmp =->(x, y) {
        return rnk[x] <=> rnk[y] if rnk[x] != rnk[y]
        rx = x + k < n ? rnk[x + k] : -1
        ry = y + k < n ? rnk[y + k] : -1
        rx <=> ry
    }

    while k < n
        sa.sort! {|x, y| cmp.call(x, y)}

        tmp[sa[0]] = 0
        1.upto(n-1) do |i|
            tmp[sa[i]] = tmp[sa[i - 1]] + (cmp.call(sa[i-1], sa[i]) == -1 ? 1 : 0)
        end

        tmp, rnk = rnk, tmp
        k <<= 1
    end
    sa
end

def sa_is(s, upper)
    n = s.size
    return [] if n == 0
    return [0] if n == 1
    return s[0] < s[1] ? [0, 1] : [1, 0] if n == 2
    return sa_naive(s) if n < 10
    return sa_doubling(s) if n < 40
    
    sa = Array.new(n)
    ls = Array.new(n)
    (n - 2).downto(0) {|i| ls[i] = s[i] == s[i + 1] ? ls[i + 1] : s[i] < s[i + 1]}

    sum_l = Array.new(upper + 1, 0)
    sum_s = Array.new(upper + 1, 0)
    n.times {|i| !ls[i] ? sum_s[s[i]] += 1 : sum_l[s[i] + 1] += 1}

    (upper + 1).times do |i|
        sum_s[i] += sum_l[i]
        sum_l[i + 1] += sum_s[i] if i < upper
    end

    induce =-> (lms) {
        sa.fill(-1)
        buf = sum_s.dup

        lms.each do |d|
            next if d == n
            sa[buf[s[d]]] = d
            buf[s[d]] += 1
        end

        buf = sum_l.dup
        sa[buf[s[n - 1]]] = n - 1
        buf[s[n - 1]] += 1
        n.times do |i|
            v = sa[i]
            if v >= 1 && !ls[v - 1]
                sa[buf[s[v - 1]]] = v - 1
                buf[s[v - 1]] += 1
            end
        end

        buf = sum_l.dup
        (n - 1).downto(0) do |i|
            v = sa[i]
            sa[buf[s[v - 1] + 1] -= 1] = v - 1 if v >= 1 && ls[v - 1]
        end
    }

    lms_map = Array.new(n+1, -1)
    m = 0
    1.upto(n - 1) {|i| (lms_map[i] = m; m += 1) if !ls[i - 1] && ls[i]}

    lms = []
    1.upto(n - 1) {|i| lms << i if !ls[i - 1] && ls[i]}

    induce.(lms)

    return sa if m == 0
    sorted_lms = []
    sa.each{|v| sorted_lms << v if lms_map[v] != -1}
    rec_s = Array.new(m)
    rec_upper = 0
    rec_s[lms_map[sorted_lms[0]]] = 0

    1.upto(m - 1) do |i|
        l = sorted_lms[i - 1]
        r = sorted_lms[i]
        end_l = lms_map[l] + 1 < m ? lms[lms_map[l] + 1] : n
        end_r = lms_map[r] + 1 < m ? lms[lms_map[r] + 1] : n
        if end_l - l != end_r - r
            rec_upper += 1
        else
            while l < end_l
                break if s[l] != s[r]
                l += 1
                r += 1
            end
            rec_upper += 1 if l == n || s[l] != s[r]
        end
        rec_s[lms_map[sorted_lms[i]]] = rec_upper
    end

    rec_sa = sa_is(rec_s, rec_upper)
    m.times{|i| sorted_lms[i] = lms[rec_sa[i]]}
    induce.(sorted_lms)
    sa
end

def s_suffix_array(s)
    sa_is(s, s.max)
end

def v_lcp_array(s, sa)
    n = s.size
    rnk = Array.new(n)
    n.times {|i| rnk[sa[i]] = i}

    lcp = Array.new(n - 1)
    h = 0
    n.times do |i|
        h -= 1 if h > 0
        next if rnk[i] == 0
        j = sa[rnk[i] - 1]
        while j + h < n && i + h < n
            break if s[j + h] != s[i + h]
            h += 1
        end
        lcp[rnk[i] - 1] = h
    end
    lcp
end

a = ?a.ord
s = gets.chomp.chars.map{|e| e.ord - a}
n = s.size
sa = s_suffix_array(s)
p v_lcp_array(s, sa).inject(n * (n+1) / 2) {|r,v| r - v}