#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/detail/standard_policies.hpp>

const double pi = 3.141592653589793238462643383279;
using namespace std;
using namespace __gnu_pbds;
//typedef
//------------------------------------------
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef pair<long long, long long> PLL;
typedef pair<int, PII> TIII;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<LL> VLL;
typedef vector<VLL> VVLL;
 
 
//container util
//------------------------------------------
#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define MP make_pair
#define SQ(a) ((a)*(a))
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())
 
 
//repetition
//------------------------------------------
#define FOR(i,s,n) for(int i=s;i<(int)n;++i)
#define REP(i,n) FOR(i,0,n)
#define MOD 1000000007
 
 
#define rep(i, a, b) for(int i = a; i < (b); ++i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
 
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
 
#define chmin(x,y) x=min(x,y)
#define chmax(x,y) x=max(x,y)

const long double EPS = 1e-6, PI = acos((long double)-1);

//ここから編集
struct SuffixArray{

  #define STYPE 1
  #define LTYPE 0

  vector<int> bkt;
  bool isLMS(const vector<int> &t, int i){
    if(i > 0 && t[i] && !t[i-1]) return true;
    return false;
  }
  void get_bucket(const vector<int> &S, const int K, bool end){
    int i, sum=0, sz = (int)S.size(); 
    for(i=0; i<K; i++) bkt[i] = 0;
    for(i=0; i<sz; i++) bkt[S[i]]++;
    
    for(i=0; i<K; i++){
      sum += bkt[i];
      bkt[i] = end ? sum : sum - bkt[i];
    }
  }

  void induceSAl(const vector<int>&t, const vector<int>&S, vector<int>& SA, int K){
    int i, j, sz = (int)S.size();
    get_bucket(S, K, false);
    for(i=0; i<sz; i++){
      j = SA[i]-1;
      if(j>=0 && !t[j]) SA[bkt[S[j]]++] = j;
    }
  }

  void induceSAs(const vector<int>&t, const vector<int>&S, vector<int>& SA, int K){
    int i, j, sz = (int)S.size();
    get_bucket(S, K, true);
    for(i=sz-1; i>=0; i--){
      j = SA[i]-1;
      if(j>=0 && t[j]) SA[--bkt[S[j]]] = j;
    }
  }

  vector<int> sa_is(const vector<int> &S, int K){
    int i, j, sz = (int)S.size(), n = sz;
    
    vector<int> t(sz, 0); // 各suffixのタイプ(S: 1, L: 0)を求める
    t[sz-1] = STYPE; t[sz-2] = LTYPE;
  
    for(i=sz-3; i>=0; i--){
      if(S[i] == S[i+1]){
        t[i] = t[i+1];
        continue;
      }
      if(S[i] < S[i+1]) t[i] = STYPE;
      else t[i] = LTYPE;
    }

    get_bucket(S, K, true);

    // induced sorting
    vector<int> SA(sz,-1);
    for(i=1; i<sz; i++) if(isLMS(t, i)) SA[--bkt[S[i]]] = i;

    induceSAl(t, S, SA, K);
    induceSAs(t, S, SA, K);

    // LMSをLMS-substringの辞書順に並べる
    int n1 = 0; // the number of LMS

    //SAの[0~n1]にはLMSのインデックスが入る
    for(i=0; i<sz; i++){
      if(isLMS(t, SA[i])) SA[n1++] = SA[i];
    }

    for(i=n1; i<n; i++) SA[i] = -1; //初期化

    int name=0, prev=-1;

    for(i=0; i<n1; i++){
      int pos = SA[i]; bool diff = false;
      for(int d = 0; d < sz; d++){
        if(prev == -1 || S[pos+d] != S[prev+d] || t[pos+d] != t[prev+d]){
          diff = true; break;
        }else if(d > 0 && (isLMS(t, pos+d) || isLMS(t, prev+d))) break;
      }
      if(diff) { name++; prev = pos; }
      pos = (pos%2 == 0)?pos/2:(pos-1)/2;
      SA[n1+pos] = name-1;
    }

    vector<int> SA1(n1, -1), S1(n1, -1), p1(n1, -1);
    int at = 0;
    for(i=n1; i<n; i++) if(SA[i] >= 0) S1[at++] = SA[i];
    if(name < n1) SA1 = sa_is(S1, name);
    else for(i = 0; i<n1; i++) SA1[S1[i]] = i;

    get_bucket(S, K, true);
    at = 0;

    for(i=1; i<n; i++) if(isLMS(t, i)) p1[at++] = i;
    fill(SA.begin(), SA.end(), -1);

    for(i=n1-1; i>=0; i--){
      j = p1[SA1[i]];
      SA[--bkt[S[j]]] = j;
    }

    induceSAl(t, S, SA, K);
    induceSAs(t, S, SA, K);
    return SA;
  }

  vector<int> get_sa(const vector<int> &S, int K=26){
    int i, sz = (int)S.size();
    vector<int> s(sz+1, 0);
    for(i=0; i<sz; i++) s[i] = S[i] + 1;
    bkt.resize(max(sz+1, K+1));
    return sa_is(s, K+1);
  }
};

void construct_lcp(string s, vector<int> sa, vector<int>&lcp){
  int n = s.size();
  vector<int> rk(n+1);
  for(int i=0; i<=n; i++) rk[sa[i]] = i;
  int h = 0;
  lcp[0] = 0;
  for(int i=0; i<n; i++){
    int j = sa[rk[i] - 1];
    if(h > 0) h--;
    for(;j+h<n && i+h<n; h++){
      if(s[j+h] != s[i+h]) break;
    }
    lcp[rk[i]-1] = h;
  }
}
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  
  int t; t = 1;
  while(t--){
    string s; cin >> s;
    ll ans = s.size()*(s.size()+1)/2;

    vector<int> tt;
    for(int i=0; i<s.size(); i++){
      tt.push_back(s[i]-'a');
    }
    SuffixArray sa;
    auto v = sa.get_sa(tt);
    vector<int> lcp(s.size());
    construct_lcp(s, v, lcp);

    for(int i=0; i<s.size(); i++) ans -= lcp[i];
    cout << ans << endl;
  }
  return 0;
}

Measured memory_bytes: 19152