use std::io::*;
use string::*;
use utils::*;

pub fn main() {
    let i = stdin();
    let mut o = Vec::new();
    run(i.lock(), &mut o).unwrap();
    stdout().write_all(&o).unwrap();
}

pub fn run(i: impl BufRead, o: &mut impl Write) -> std::io::Result<()> {
    let mut i = CpReader::new(i);
    let s = i.read_line();
    let sa = suffix_array(&s, Some(b'z'));
    let lcp = lcp_array(s, &sa);
    let lcp_sum: usize = lcp.iter().sum();
    let ans = s.len() * (s.len() + 1) / 2 - lcp_sum;
    writeln!(o, "{}", ans)?;
    Ok(())
}

pub mod utils {
    use super::*;

    pub struct CpReader<R: BufRead> {
        r: R,
        b: Vec<u8>,
    }
    impl<R: BufRead> CpReader<R> {
        pub fn new(r: R) -> Self {
            CpReader {
                r: r,
                b: Vec::new(),
            }
        }
        pub fn read_word(&mut self) -> &[u8] {
            self.b.clear();
            loop {
                let b = self.r.fill_buf().unwrap();
                assert!(!b.is_empty());
                if let Some(p) = b.iter().position(|&x| x == b' ' || x == b'\n') {
                    self.b.extend_from_slice(&b[..p]);
                    self.r.consume(p + 1);
                    return &self.b;
                }
                self.b.extend_from_slice(b);
                let b_len = b.len();
                self.r.consume(b_len);
            }
        }
        pub fn read_word_str(&mut self) -> &str {
            unsafe { std::str::from_utf8_unchecked(self.read_word()) }
        }

        pub fn read_line(&mut self) -> &[u8] {
            self.b.clear();
            self.r.read_until(b'\n', &mut self.b).unwrap();
            if self.b.last() == Some(&b'\n') {
                &self.b[..self.b.len() - 1]
            } else {
                &self.b
            }
        }
        pub fn read_line_str(&mut self) -> &str {
            unsafe { std::str::from_utf8_unchecked(self.read_line()) }
        }

        pub fn read<T: CpIn>(&mut self) -> T {
            T::read_from(self)
        }

        pub fn read_vec<T: CpIn>(&mut self, n: usize) -> Vec<T> {
            (0..n).map(|_| self.read()).collect()
        }
        pub fn read_iter<'a, T: CpIn>(&'a mut self, n: usize) -> CpIter<'a, R, T> {
            CpIter {
                r: self,
                n: n,
                _pd: Default::default(),
            }
        }
    }
    pub struct CpIter<'a, R: BufRead + 'a, T> {
        r: &'a mut CpReader<R>,
        n: usize,
        _pd: std::marker::PhantomData<fn() -> T>,
    }
    impl<'a, R: BufRead, T: CpIn> Iterator for CpIter<'a, R, T> {
        type Item = T;
        fn next(&mut self) -> Option<T> {
            if self.n == 0 {
                None
            } else {
                self.n -= 1;
                Some(self.r.read())
            }
        }
        fn size_hint(&self) -> (usize, Option<usize>) {
            (self.n, Some(self.n))
        }
    }
    impl<'a, R: BufRead, T: CpIn> ExactSizeIterator for CpIter<'a, R, T> {}

    pub trait CpIn {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self;
    }

    impl CpIn for u64 {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            read_u64_fast(&mut r.r)
        }
    }
    impl CpIn for i64 {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            read_i64_fast(&mut r.r)
        }
    }
    impl CpIn for char {
        fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
            let b = r.r.fill_buf().unwrap()[0] as char;
            r.r.consume(1);
            let s = r.r.fill_buf().unwrap()[0];
            assert!(s == b' ' || s == b'\n');
            r.r.consume(1);
            b
        }
    }

    macro_rules! cpin_tuple {
        ($($t:ident),*) => {
            impl<$($t: CpIn),*> CpIn for ($($t),*) {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    ($($t::read_from(r)),*)
                }
            }
        };
    }

    macro_rules! cpin_cast {
        ($t_self:ty, $t_read:ty) => {
            impl CpIn for $t_self {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    <$t_read>::read_from(r) as $t_self
                }
            }
        };
    }
    macro_rules! cpin_parse {
        ($t:ty) => {
            impl CpIn for $t {
                fn read_from<R: BufRead>(r: &mut CpReader<R>) -> Self {
                    r.read_word_str().parse().unwrap()
                }
            }
        };
    }
    cpin_cast!(usize, u64);
    cpin_cast!(u32, u64);
    cpin_cast!(u16, u64);
    cpin_cast!(i32, i64);
    cpin_cast!(i16, i64);
    cpin_cast!(i8, i64);

    cpin_parse!(f64);

    cpin_tuple!(T1, T2);
    cpin_tuple!(T1, T2, T3);
    cpin_tuple!(T1, T2, T3, T4);
    cpin_tuple!(T1, T2, T3, T4, T5);

    fn read_u64_fast<R: BufRead>(r: &mut R) -> u64 {
        let mut value = 0;
        loop {
            let buf = r.fill_buf().unwrap();
            assert!(!buf.is_empty());
            let mut idx = 0;
            while let Some(&c) = buf.get(idx) {
                if b'0' <= c && c <= b'9' {
                    value = value * 10 + (c - b'0') as u64;
                    idx += 1;
                } else {
                    r.consume(idx + 1);
                    return value;
                }
            }
            r.consume(idx);
        }
    }
    fn read_i64_fast<R: BufRead>(r: &mut R) -> i64 {
        let sign = match r.fill_buf().unwrap()[0] {
            b'+' => {
                r.consume(1);
                1
            }
            b'-' => {
                r.consume(1);
                -1
            }
            _ => 1,
        };
        read_u64_fast(r) as i64 * sign
    }
}
mod string {
    #![allow(dead_code)]

    use std::{cmp::min, cmp::Ordering, mem::swap};

    fn sa_navie<T: Ord>(s: &[T]) -> Vec<usize> {
        let mut sa: Vec<usize> = (0..s.len()).collect();
        sa.sort_by(|&l, &r| {
            if l == r {
                Ordering::Equal
            } else {
                s[l..].cmp(&s[r..])
            }
        });
        sa
    }

    fn sa_doubling(s: &[usize]) -> Vec<usize> {
        let n = s.len();
        let mut sa: Vec<usize> = (0..n).collect();
        let mut rnk: Vec<usize> = s.to_vec();
        let mut tmp = vec![0; n];
        let mut k = 1;
        while k < s.len() {
            let cmp = |x: &usize, y: &usize| {
                let x = *x;
                let y = *y;
                if rnk[x] != rnk[y] {
                    rnk[x].cmp(&rnk[y])
                } else {
                    let rx = if x + k < n { Some(rnk[x + k]) } else { None };
                    let ry = if y + k < n { Some(rnk[y + k]) } else { None };
                    rx.cmp(&ry)
                }
            };
            sa.sort_by(cmp);
            tmp[sa[0]] = 0;
            for i in 1..n {
                tmp[sa[i]] = tmp[sa[i - 1]]
                    + if cmp(&sa[i - 1], &sa[i]) == Ordering::Less {
                        1
                    } else {
                        0
                    };
            }
            swap(&mut tmp, &mut rnk);
            k *= 2;
        }
        sa
    }

    fn sa_is(s: &[usize], upper: usize) -> Vec<usize> {
        sa_is_with(s, upper, 10, 40)
    }

    fn sa_is_with(
        s: &[usize],
        upper: usize,
        threshold_navie: usize,
        threshold_doubling: usize,
    ) -> Vec<usize> {
        match s.len() {
            0 => return vec![],
            1 => return vec![0],
            2 => return if s[0] < s[1] { vec![0, 1] } else { vec![1, 0] },
            _ => {}
        }
        if s.len() <= threshold_navie {
            return sa_navie(s);
        }
        if s.len() <= threshold_doubling {
            return sa_doubling(s);
        }
        let mut sa = vec![0; s.len()];
        let mut ls = vec![false; s.len()];
        for i in (0..=s.len() - 2).rev() {
            ls[i] = if s[i] == s[i + 1] {
                ls[i + 1]
            } else {
                s[i] < s[i + 1]
            };
        }
        let mut sum_l = vec![0; upper + 1];
        let mut sum_s = vec![0; upper + 1];

        for i in 0..s.len() {
            if !ls[i] {
                sum_s[s[i]] += 1;
            } else {
                sum_l[s[i] + 1] += 1;
            }
        }
        for i in 0..=upper {
            sum_s[i] += sum_l[i];
            if i < upper {
                sum_l[i + 1] += sum_s[i];
            }
        }
        let induce = |sa: &mut [usize], lms: &[usize]| {
            for i in sa.iter_mut() {
                *i = 0;
            }
            let mut buf = sum_s.clone();
            for &d in lms {
                if d != s.len() {
                    let b = &mut buf[s[d]];
                    sa[*b] = d + 1;
                    *b += 1;
                }
            }
            buf.copy_from_slice(&sum_l);
            let b = &mut buf[s[s.len() - 1]];
            sa[*b] = s.len();
            *b += 1;
            for i in 0..s.len() {
                let v = sa[i];
                if v >= 2 && !ls[v - 2] {
                    let b = &mut buf[s[v - 2]];
                    sa[*b] = v - 1;
                    *b += 1;
                }
            }
            buf.copy_from_slice(&sum_l);
            for i in (0..s.len()).rev() {
                let v = sa[i];
                if v >= 2 && ls[v - 2] {
                    let b = &mut buf[s[v - 2] + 1];
                    *b -= 1;
                    sa[*b] = v - 1;
                }
            }
        };

        let mut lms_map = vec![usize::max_value(); s.len() + 1];
        let mut m = 0;
        for i in 1..s.len() {
            if !ls[i - 1] && ls[i] {
                lms_map[i] = m;
                m += 1;
            }
        }
        let mut lms = Vec::with_capacity(m);
        for i in 1..s.len() {
            if !ls[i - 1] && ls[i] {
                lms.push(i);
            }
        }
        induce(&mut sa, &lms);

        if m != 0 {
            let mut sorted_lms = Vec::with_capacity(m);
            for v in &sa {
                let v = v - 1;
                if lms_map[v] != usize::max_value() {
                    sorted_lms.push(v);
                }
            }
            let mut rec_s = vec![0; m];
            let mut rec_upper = 0;
            rec_s[lms_map[sorted_lms[0]]] = 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] + 1 < m {
                    lms[lms_map[l] + 1]
                } else {
                    s.len()
                };
                let end_r = if lms_map[r] + 1 < m {
                    lms[lms_map[r] + 1]
                } else {
                    s.len()
                };
                let mut same = true;
                if end_l - l != end_r - r {
                    same = false;
                } else {
                    while l < end_l {
                        if s[r] != s[l] {
                            break;
                        }
                        l += 1;
                        r += 1;
                    }
                    if l == s.len() || s[l] != s[r] {
                        same = false;
                    }
                }
                if !same {
                    rec_upper += 1;
                }
                rec_s[lms_map[sorted_lms[i]]] = rec_upper;
            }
            let rec_sa = sa_is_with(&rec_s, rec_upper, threshold_navie, threshold_doubling);
            for i in 0..m {
                sorted_lms[i] = lms[rec_sa[i]];
            }
            induce(&mut sa, &sorted_lms);
        }
        for x in &mut sa {
            *x -= 1;
        }
        sa
    }

    pub fn suffix_array_usize(s: &[usize], upper: Option<usize>) -> Vec<usize> {
        let upper = if let Some(upper) = upper {
            debug_assert!(s.iter().all(|&x| x <= upper));
            upper
        } else {
            s.iter().cloned().max().unwrap_or(0)
        };
        sa_is(s, upper)
    }

    pub fn suffix_array_ord<T: Ord>(s: &[T]) -> Vec<usize> {
        let mut idx: Vec<usize> = (0..s.len()).collect();
        idx.sort_by_key(|&x| &s[x]);
        let mut s2 = vec![0; s.len()];
        let mut now = 0;
        for i in 0..s.len() {
            if i != 0 && s[idx[i - 1]] != s[idx[i]] {
                now += 1;
            }
            s2[idx[i]] = now;
        }
        sa_is(&s2, now)
    }
    pub fn suffix_array<T: Into<usize> + Copy>(s: &[T], upper: Option<T>) -> Vec<usize> {
        let s: Vec<usize> = s.iter().map(|&x| x.into()).collect();
        suffix_array_usize(&s, upper.map(|x| x.into()))
    }

    pub fn lcp_array<T: PartialEq>(s: &[T], sa: &[usize]) -> Vec<usize> {
        debug_assert!(s.len() >= 1);
        let mut rnk = vec![0; s.len()];
        for i in 0..s.len() {
            rnk[sa[i]] = i;
        }
        let mut lcp = vec![0; s.len() - 1];
        let mut h = 0;
        for i in 0..s.len() {
            if h > 0 {
                h -= 1;
            }
            if rnk[i] == 0 {
                continue;
            }
            let j = sa[rnk[i] - 1];
            while let (Some(vj), Some(vi)) = (s.get(j + h), s.get(i + h)) {
                if vj != vi {
                    break;
                }
                h += 1;
            }
            lcp[rnk[i] - 1] = h;
        }
        lcp
    }

    pub fn z_algorithm<T: Ord>(s: &[T]) -> Vec<usize> {
        if s.is_empty() {
            return vec![];
        }
        let mut z = vec![0; s.len()];
        z[0] = 0;
        let mut j = 0;
        for i in 1..s.len() {
            z[i] = if j + z[j] <= i {
                0
            } else {
                min(j + z[j] - i, z[i - j])
            };
            let k = &mut z[i];
            while i + *k < s.len() && s[*k] == s[i + *k] {
                *k += 1;
            }
            if j + z[j] < i + z[i] {
                j = i;
            }
        }
        z[0] = s.len();
        z
    }
}


Measured memory_bytes: 26856