#include <bits/stdc++.h>
using namespace std;
int dy[] = {1, -1, 0, 0, -1, 1, 1, -1};
int dx[] = {0, 0, 1, -1, 1, -1, 1, -1};
void file() {}
void fast() {
  std::ios_base::sync_with_stdio(0);
  cin.tie(NULL);
}
class SuffixArray {
 public:
  int n, alpha = 128;
  string str;
  vector<int> suff, rnk, lcp;
  SuffixArray(string s) {
    str = s;
    str.push_back('\0');
    n = (int)(str.size());
    suff = rnk = lcp = vector<int>(n);
    build_suffix_array();
    build_LCP_array();
  }
  void build_suffix_array() {
    vector<int> bucket_idx(n), newrnk(n), newsuff(n), prev(n), head(alpha, -1);
    for (int i = 0; i < n; i++) {
      prev[i] = head[str[i]];
      head[str[i]] = i;
    }
    int buc = -1, idx = 0;
    for (int i = 0; i < alpha; i++) {
      if (head[i] == -1) continue;
      bucket_idx[++buc] = idx;
      for (int j = head[i]; ~j; j = prev[j]) suff[idx++] = j, rnk[j] = buc;
    }
    int cur_cmp = 1;
    do {
      auto cmp = [&](int a, int b) {
        return rnk[a] < rnk[b] ||
               rnk[a] == rnk[b] && rnk[a + cur_cmp] < rnk[b + cur_cmp];
      };
      for (int i = 0; i < n; i++) {
        int j = suff[i] - cur_cmp;
        if (j < 0) continue;
        newsuff[bucket_idx[rnk[j]]++] = j;
      }
      for (int i = 1; i < n; i++) {
        suff[i] = newsuff[i];
        bool cmpres = cmp(suff[i - 1], suff[i]);
        newrnk[suff[i]] = newrnk[suff[i - 1]] + cmpres;
        if (cmpres) bucket_idx[newrnk[suff[i]]] = i;
      }
      rnk = newrnk;
      cur_cmp <<= 1;
    } while (rnk[suff[n - 1]] != n - 1);
  }
  void build_LCP_array() {
    int cnt = 0;
    for (int i = 0; i < n - 1; i++) {
      int j = suff[rnk[i] - 1];
      while (str[i + cnt] == str[j + cnt]) cnt++;
      lcp[rnk[i]] = cnt;
      if (cnt) cnt--;
    }
  }
  void print_suffix_array() {
    for (int i = 0; i < n; i++)
      cout << str.substr(suff[i]) << ' ' << lcp[i] << '\n';
  }
};
long long solve(string str) {
  map<string, long long> mp;
  long long ret = 0;
  for (int i = 0; i < (int)(str.size()); i++) {
    for (int j = i; j < (int)(str.size()); j++) {
      mp[str.substr(i, j - i + 1)]++;
    }
  }
  for (auto& it : mp) ret += it.second * (it.second + 1LL) / 2;
  return ret;
}
template <typename T>
struct sparse_table {
  vector<vector<T>> sparseTable;
  vector<T> arr;
  vector<int> LOG2;
  int merge(int a, int b) {
    if (arr[a] < arr[b]) return a;
    return b;
  }
  void build_LOG2() {
    LOG2[0] = -1;
    for (int i = 1; i < (int)(LOG2.size()); i++) LOG2[i] = LOG2[i >> 1] + 1;
  }
  sparse_table(vector<T>& v) {
    arr = v;
    int n = v.size();
    LOG2 = vector<int>(n + 1);
    build_LOG2();
    sparseTable = vector<vector<T>>(LOG2[n] + 1);
    sparseTable[0].resize(n);
    iota(sparseTable[0].begin(), sparseTable[0].end(), 0);
    for (int k = 1, len = 1; k <= LOG2[n]; k++, len <<= 1) {
      sparseTable[k].resize(n);
      for (int i = 0; i + len < n; i++)
        sparseTable[k][i] =
            merge(sparseTable[k - 1][i], sparseTable[k - 1][i + len]);
    }
  }
  T query(int l, int r) {
    int k = LOG2[r - l + 1];
    return merge(sparseTable[k][l], sparseTable[k][r - (1 << k) + 1]);
  }
};
int main() {
  file();
  fast();
  string str;
  cin >> str;
  int n = (int)(str.size());
  SuffixArray sa(str);
  long long ans = n * (n + 1LL) / 2;
  vector<int> v1(sa.lcp.begin() + 1, sa.lcp.end());
  sparse_table<int> sp(v1);
  queue<pair<pair<int, int>, int>> q;
  q.push({{0, n - 1}, 0});
  while (!q.empty()) {
    int l = q.front().first.first, r = q.front().first.second;
    int del = q.front().second;
    q.pop();
    if (l > r) continue;
    int idx = sp.query(l, r);
    if (v1[idx] == del) {
      q.push({{l, idx - 1}, del});
      q.push({{idx + 1, r}, del});
      continue;
    }
    int cnt = v1[idx] - del, s = r - l + 2;
    ans += ((s * (s + 1LL) / 2) * cnt - 1LL * s * cnt);
    del += cnt;
    q.push({{l, idx - 1}, del});
    q.push({{idx + 1, r}, del});
  }
  cout << ans << '\n';
  return 0;
}
