// template {{{
#![allow(clippy::many_single_char_names)]

#[allow(dead_code)]
mod ngtio {
    use ::std::collections::VecDeque;

    pub struct Buffer {
        buf: VecDeque<String>,
    }

    impl Buffer {
        pub fn new() -> Self {
            Self {
                buf: VecDeque::new(),
            }
        }

        fn load(&mut self) {
            while self.buf.is_empty() {
                let mut s = String::new();
                let length = ::std::io::stdin().read_line(&mut s).unwrap();
                if length == 0 {
                    break;
                }
                self.buf.extend(s.split_whitespace().map(|s| s.to_owned()));
            }
        }

        pub fn string(&mut self) -> String {
            self.load();
            self.buf
                .pop_front()
                .unwrap_or_else(|| panic!("入力が終了したのですが。"))
        }

        pub fn string_char_vec(&mut self) -> Vec<char> {
            let s = self.string();
            s.chars().collect::<Vec<_>>()
        }

        pub fn string_char_vec_trusted_len(&mut self, len: usize) -> Vec<char> {
            let s = self.string();
            let s = s.chars().collect::<Vec<_>>();
            assert_eq!(s.len(), len, "あら、思ったのと長さ違いますね……");
            s
        }

        pub fn char(&mut self) -> char {
            let string = self.string();
            let mut chars = string.chars();
            let res = chars.next().unwrap();
            assert!(
                chars.next().is_none(),
                "char で受け取りたいのも山々なのですが、さては 2 文字以上ありますね？"
            );
            res
        }

        pub fn read<T: ::std::str::FromStr>(&mut self) -> T
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            self.string()
                .parse::<T>()
                .expect("Failed to parse the input.")
        }

        pub fn read_vec<T: ::std::str::FromStr>(&mut self, len: usize) -> Vec<T>
        where
            <T as ::std::str::FromStr>::Err: ::std::fmt::Debug,
        {
            (0..len).map(|_| self.read::<T>()).collect()
        }
    }

    macro_rules! define_primitive_reader {
        ($($ty:tt,)*) => {
            impl Buffer {
                $(
#[inline]
                    pub fn $ty(&mut self) -> $ty {
                        self.read::<$ty>()
                    }
                )*
            }
        }
    }

    define_primitive_reader! {
        u8, u16, u32, u64, usize,
        i8, i16, i32, i64, isize,
    }

    impl Default for Buffer {
        fn default() -> Self {
            Self::new()
        }
    }
}

#[allow(unused_imports)]
use std::{collections, iter, mem, ops};
// }}}
// suffix_array {{{
#[allow(dead_code)]
mod suffix_array {
    #![warn(missing_docs)]
    #![warn(missing_doc_code_examples)]

    pub fn suffix_array<T: Ord>(s: &[T]) -> Vec<usize> {
        let n = s.len();
        let mut ord: Vec<usize> = (0..n).collect();
        ord.sort_by_key(|&i| &s[i]);
        let mut cmp = vec![0; n];
        for i in 1..n {
            cmp[i] = if s[ord[i - 1]] == s[ord[i]] {
                cmp[i - 1]
            } else {
                cmp[i - 1] + 1
            };
        }
        for d in std::iter::successors(Some(1), |x| Some(x * 2)).take_while(|&x| x <= n) {
            let mut ord_inverse = vec![0; n];
            (0..n).for_each(|i| ord_inverse[ord[i]] = i);
            let cmp_count = *cmp.last().unwrap() + 1;
            let mut pos = vec![0; cmp_count];
            for (i, &c) in cmp.iter().enumerate().rev() {
                pos[c] = i;
            }

            let mut ord_swp = vec![0; n];
            let mut insert = |i| {
                let c = cmp[ord_inverse[i]];
                ord_swp[pos[c]] = i;
                pos[c] += 1;
            };
            (n - d..n).for_each(&mut insert);
            ord.iter()
                .filter(|&&i| d <= i)
                .map(|i| i - d)
                .for_each(insert);

            let mut cmp_swp = vec![0; n];
            for i in 1..n {
                let l = ord_swp[i - 1];
                let r = ord_swp[i];
                cmp_swp[i] = if (
                    cmp[ord_inverse[l]],
                    ord_inverse.get(l + d).map(|&ld| cmp[ld]).unwrap_or(n),
                ) == (
                    cmp[ord_inverse[r]],
                    ord_inverse.get(r + d).map(|&rd| cmp[rd]).unwrap_or(n),
                ) {
                    cmp_swp[i - 1]
                } else {
                    cmp_swp[i - 1] + 1
                }
            }

            ord = ord_swp;
            cmp = cmp_swp;
        }
        ord
    }

    pub fn lcp_array<T: Ord>(s: &[T], sa: &[usize]) -> Vec<usize> {
        assert_eq!(s.len(), sa.len());
        assert!(!s.is_empty());
        assert!(!sa.is_empty());

        let n = s.len();
        let rnk = make_rank(&sa);
        let mut h = 0usize;
        let mut lcp = vec![0; n - 1];
        for (i, &r) in rnk.iter().enumerate() {
            h = h.saturating_sub(1);
            if r != 0 {
                let j = sa[r - 1];
                h = (h..)
                    .find(|&h| j + h == n || i + h == n || s[j + h] != s[i + h])
                    .unwrap();
                lcp[r - 1] = h;
            }
        }
        lcp
    }

    fn make_rank(a: &[usize]) -> Vec<usize> {
        let n = a.len();
        let mut b = vec![n; n];
        for (i, &x) in a.iter().enumerate() {
            assert_eq!(b[x], n);
            b[x] = i;
        }
        b
    }
}
// }}}

fn main() {
    let mut buf = ngtio::Buffer::new();
    let s = buf.string();
    let n = s.bytes().len();
    let sa = suffix_array::suffix_array(s.as_bytes());
    let lcp = suffix_array::lcp_array(s.as_bytes(), &sa);
    let ans = n * (n + 1) / 2 - lcp.iter().sum::<usize>();
    println!("{}", ans);
}


Measured memory_bytes: 31764