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 PHP (7.4.4) (judge verdict: Accepted)

<?php


class StringClass
{
    private int $n;
    private int $upper;

    /**
     * 長さ n の文字列 s のSuffix Arrayとして、長さ nn の vector を返す。<br>
     * Suffix Array sa は (0,1,…,n−1) の順列であって、各i=0,1,⋯,n−2 について s[sa[i]..n) < s[sa[i+1]..n) を満たすもの。<br>
     * 制約<br>
     * 0 ≤ n < 10^8 (PHPでは 10^6位が限界？)<br>
     * 計算量<br>
     * O(n)
     * @param string $str 文字列
     * @return array|int[]
     */
    public function suffix_array(string $str){
        $array = str_split($str);
        for($i=0;$i<count($array);$i++){
            $array[$i] = ord($array[$i]);
        }
        return $this->sa_is($array, 255);
    }

    /**
     * arrayの数字が非連続の場合に使う？
     * O(nlogn)
     * @param array $array
     * @return array|int[]
     */
    public function suffix_array_array(array $array){
        $s = $array;
        asort($array);
        $last = PHP_INT_MIN;
        $now = 0;
        foreach($array as $key => $value){
            if($last !== $value){
                $now++;
                $last = $value;
            }
            $s[$key] = $now;
        }
        return $this->sa_is($s,$now);
    }
//
//    function sa_native(array $s):array{
//        $sa = [];
//        $tmp = "";
//        for($i = count($s) -1 ; $i>=0;$i--){
//            $tmp = chr($s[$i]) . $tmp;
//            $sa[$i] = $tmp;
//        }
//        asort($sa);
//        return array_keys($sa);
//
//    }

    /**
     *　数字配列と上限数がわかっている場合に使う？
     * 数字が抜けている場合、suffix_array_arrayの場合が高速になり得る。
     * 計算量 O(n+upper)
     * @param int[] $s
     * @param int $upper
     * @return array|int[]
     */
    public function sa_is(array $s,int $upper): array
    {
        $this->n = count($s);
        $this->upper = $upper;
        if ($this->n === 0) {
            return [];
        }
        if ($this->n === 1) {
            return [0];
        }
        if ($this->n === 2) {
            return ($s[0] < $s[1]) ? [0, 1] : [1, 0];
        }
//        if($this->n < 10000000){
//            return $this->sa_native($s);
//        }
        $ls = array_fill(0, $this->n , 0);
        for ($i = $this->n - 2; $i >= 0; $i--) {
            $ls[$i] = ($s[$i] === $s[$i + 1]) ? $ls[$i+1] : ($s[$i] < $s[$i + 1]);
        }
        $sum_l = $sum_s = array_fill(0, $upper + 1, 0);
        for ($i = 0; $i < $this->n; $i++) {
            if (!$ls[$i]) {
                $sum_s[$s[$i]]++;
            } else {
                $sum_l[$s[$i] + 1]++;
            }
        }
        for($i=0;$i<=$upper;$i++){
            $sum_s[$i] += $sum_l[$i];
            if($i<$upper){
                $sum_l[$i+1] += $sum_s[$i];
            }
        }
        $lms_map = array_fill(0,$this->n+1, -1);
        $m = 0;
        $lms = [];
        for($i=1;$i<$this->n;$i++){
            if(!$ls[$i-1] && $ls[$i]){
                $lms_map[$i] = $m++;
                $lms[] = $i;
            }
        }
        $sa = $this->induce($lms, $s, $sum_s, $sum_l, $ls);
        if($m){
            $sorted_lms = [];
            foreach($sa as $v){
                if($lms_map[$v] != -1){
                    $sorted_lms[] = $v;
                }
            }
            $rec_s = array_fill(0,$m,0);
            $rec_upper = 0;
            $rec_s[$lms_map[$sorted_lms[0]]] = 0;
            for($i=1;$i<$m;$i++){
                $l = $sorted_lms[$i-1];
                $r = $sorted_lms[$i];
                $end_l = ($lms_map[$l] + 1 < $m)? $lms[$lms_map[$l] + 1]: $this->n;
                $end_r = ($lms_map[$r] + 1 < $m)? $lms[$lms_map[$r] + 1]: $this->n;
                $same = true;
                if($end_l - $l != $end_r - $r){
                    $same = false;
                }else{
                    while($l < $end_l){
                        if($s[$l] != $s[$r]){
                            break;
                        }
                        $l++;
                        $r++;
                    }
                    if($l===$this->n || $s[$l] != $s[$r] ){
                        $same = false;
                    }
                }
                if(!$same){
                    $rec_upper++;
                }
                $rec_s[$lms_map[$sorted_lms[$i]]] = $rec_upper;
            }
            $n = $this->n;
            $rec_sa = $this->sa_is($rec_s, $rec_upper+1);
            $this->n = $n;
            for($i=0;$i<$m;$i++){
                $sorted_lms[$i] = $lms[$rec_sa[$i]];
            }
            $sa = $this->induce($sorted_lms, $s, $sum_s, $sum_l, $ls);
        }
        return $sa;
    }

    function induce($lms, $s, $sum_s, $sum_l, $ls){

        $sa = array_fill(0,$this->n,-1);
        $buf = $sum_s;
        foreach($lms as $d){
            if($d === $this->n){
                continue;
            }
            $sa[($buf[$s[$d]]++)] = $d;
        }
        $buf = $sum_l;
        $sa[$buf[$s[$this->n - 1]]++] = $this->n -1;
        for($i=0;$i<$this->n;$i++){
            if($sa[$i] >= 1&& !$ls[$sa[$i] - 1]){
                $sa[$buf[$s[$sa[$i] - 1]]++] = $sa[$i] - 1;
            }
        }
        $buf = $sum_l;
        for($i=$this->n-1;$i>=0;$i--){
            if($sa[$i] >= 1 && $ls[$sa[$i] - 1]){
                $sa[--$buf[$s[$sa[$i] - 1] + 1]] = $sa[$i] - 1;
            }
        }
        return $sa;
    }

    function lcp_array($s, $sa)
    {
        $n = strlen($s);
        assert($n >= 1);
        $rnk = array_fill(0, $n, 0);
        for ($i = 0; $i < $n; $i++) {
            $rnk[$sa[$i]] = $i;
        }
        $lcp = array_fill(0, $n - 1, 0);
        $h = 0;
        for ($i = 0; $i < $n; $i++) {
            if ($h > 0) {
                $h--;
            }
            if ($rnk[$i] === 0) {
                continue;
            }
            $j = $sa[$rnk[$i] - 1];
            for (; (($j + $h) < $n) && (($i + $h) < $n); $h++) {
                if ($s[$j + $h] != $s[$i + $h]) {
                    break;
                }
            }
            $lcp[$rnk[$i] - 1] = $h;
        }
        return $lcp;
    }
}

$cls = new StringClass();
[$input] = fscanf(STDIN, "%s");

$sa = $cls->suffix_array($input);
$len = strlen($input);
$ans = $len * ($len + 1) / 2;
foreach($cls->lcp_array($input, $sa) as $value){
    $ans -= $value;
}
echo $ans;