// practice with rainboy
import java.io.*;
import java.util.*;

public class CF123D extends PrintWriter {
	CF123D() { super(System.out, true); }
	Scanner sc = new Scanner(System.in);
	public static void main(String[] $) {
		CF123D o = new CF123D(); o.main(); o.flush();
	}

	byte[] cc;
	int[] sa, a0, a1, kk, pp;
	Integer[] ii;
	void compress(int n) {
		for (int i = 0, a = 1; i < n; i++)
			a0[sa[i]] = i + 1 == n || a0[sa[i + 1]] != a0[sa[i]] || a1[sa[i + 1]] != a1[sa[i]] ? a++ : a;
	}
	void init(int n) {
		sa = new int[n]; a0 = new int[n]; a1 = new int[n];
		kk = new int[n + 1]; pp = new int[n];
		ii = new Integer[n];
		for (int i = 0; i < n; i++)
			ii[i] = i;
		Arrays.sort(ii, (i, j) -> cc[i] - cc[j]);
		for (int i = 0; i < n; i++)
			sa[i] = ii[i];
		for (int i = 0; i < n; i++)
			a0[i] = cc[i];
		compress(n);
	}
	void sort(int[] ii, int[] jj, int[] aa, int n) {
		Arrays.fill(kk, 0);
		for (int i = 0; i < n; i++) {
			int a = aa[i];
			kk[a]++;
		}
		for (int a = 0, k, l = 0; a <= n; a++) {
			k = kk[a]; kk[a] = l; l += k;
		}
		for (int i = 0; i < n; i++) {
			int j = ii[i], a = aa[j];
			jj[kk[a]++] = j;
		}
	}
	void build(int n) {
		init(n);
		for (int m = 1; m < n; m <<= 1) {
			for (int i = 0; i < n; i++)
				a1[i] = i + m < n ? a0[i + m] : 0;
			sort(sa, pp, a1, n);
			sort(pp, sa, a0, n);
			compress(n);
		}
		for (int i = 0, p = 0; i < n; i++, p--) {
			int a = a0[i] - 1;
			if (a + 1 < n) {
				int j = sa[a + 1];
				if (p < 0)
					p = 0;
				while (i + p < n && cc[i + p] == cc[j + p])
					p++;
				pp[a] = p;
			}
		}
		pp[n - 1] = -1;
	}
	void main() {
		cc = sc.next().getBytes();
		int n = cc.length;
		build(n);
		Arrays.sort(ii, (i, j) -> pp[i] - pp[j]);
		int[] ll = new int[n];
		int[] rr = new int[n];
		for (int a = 0; a < n; a++)
			ll[a] = rr[a] = a;
		long ans = (long) n * (n + 1) / 2, cnt = 0;
		for (int p = n - 1, i = n - 1, a; p > 0; p--) {
			while (i > 0 && pp[a = ii[i]] == p) {
				cnt += (long) (rr[a] - ll[a] + 1) * (rr[a + 1] - ll[a + 1] + 1);
				int l = ll[a], r = rr[a + 1]; rr[l] = r; ll[r] = l;
				i--;
			}
			ans += cnt;
		}
		println(ans);
	}
}


import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class CF123_D1_D{
	public static void main(String[] args)throws Throwable {
		MyScanner sc=new MyScanner();
		PrintWriter pw=new PrintWriter(System.out);

		char [] s=sc.next().toCharArray();
		SA=new SuffixAutomaton(s);
		int n=SA.idx+1;
		acceptState=new boolean [n];
		int cur=SA.idx;
		while(true){
			acceptState[cur]=true;
			if(cur==0)
				break;
			cur=SA.link[cur];
		}
		cnt=new long [n];
		Arrays.fill(cnt, -1);
		long ans=0;
		for(int i=0;i<=SA.idx;i++){
			long x=dfs(i);
			int cnt=SA.len[i]-SA.len[SA.link[i]];
			ans+=x*(x+1)*cnt/2;
		}
		pw.println(ans);
		pw.flush();
		pw.close();
	}
	static SuffixAutomaton SA;
	static boolean [] acceptState;
	static long [] cnt;

	static long dfs(int u){
		if(cnt[u]!=-1)
			return cnt[u];
		long ans=acceptState[u]? 1 : 0;
		for(Entry<Character, Integer> e : SA.nxt[u].entrySet()){
			int v=e.getValue();
			ans+=dfs(v);
		}
		return cnt[u]=ans;
	}

	static class SuffixAutomaton {
		int [] link,len;
		TreeMap<Character, Integer> [] nxt;
		int lst, idx;

		SuffixAutomaton(char [] s){
			int n=s.length;
			link=new int [n<<1];
			len=new int [n<<1];
			nxt=new TreeMap [n<<1];
			nxt[0]=new TreeMap<Character, Integer>();
			for(char c : s)
				addLeter(c);
		}

		void addLeter(char c){
			int cur = ++idx;
			int p=lst;
			while(!nxt[p].containsKey(c)){
				nxt[p].put(c, cur);
				p=link[p];
			}
			int q=nxt[p].get(c);

			// a node containing an edge with character c stopped me and it is not the root
			if(q!=cur){
				if(len[q]==len[p]+1)
					link[cur]=q;
				else{
					int clone=++idx;
					len[clone]=len[p]+1;
					link[clone]=link[q];
					nxt[clone]=new TreeMap<Character, Integer>(nxt[q]);
					link[cur]=link[q]=clone;
					while(nxt[p].get(c)==q){
						nxt[p].put(c, clone);
						p=link[p];
					}
				}
			}
			len[cur]=len[lst]+1;
			nxt[cur]=new TreeMap<Character, Integer>();
			lst=cur;
		}

	}

	static class MyScanner {
		BufferedReader br;
		StringTokenizer st;
		public MyScanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {while (st == null || !st.hasMoreElements()) {
			try {st = new StringTokenizer(br.readLine());}
			catch (IOException e) {e.printStackTrace();}}
		return st.nextToken();}
		int nextInt() {return Integer.parseInt(next());}
		long nextLong() {return Long.parseLong(next());}
		double nextDouble() {return Double.parseDouble(next());}
		String nextLine(){String str = "";
		try {str = br.readLine();}
		catch (IOException e) {e.printStackTrace();}
		return str;}
	}
}


import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class CF123_D1_D{
	public static void main(String[] args)throws Throwable {
		MyScanner sc=new MyScanner();
		PrintWriter pw=new PrintWriter(System.out);

		char [] s=sc.next().toCharArray();
		SA=new SuffixAutomaton(s);
		int n=SA.idx+1;
		acceptState=new boolean [n];
		int cur=SA.lst;
		while(true){
			acceptState[cur]=true;
			if(cur==0)
				break;
			cur=SA.link[cur];
		}
		cnt=new long [n];
		Arrays.fill(cnt, -1);
		long ans=0;
		for(int i=0;i<=SA.idx;i++){
			long x=dfs(i);
			int cnt=SA.len[i]-SA.len[SA.link[i]];
			ans+=(x*(x+1)/2)*cnt;
		}
		pw.println(ans);
		pw.flush();
		pw.close();
	}
	static SuffixAutomaton SA;
	static boolean [] acceptState;
	static long [] cnt;

	static long dfs(int u){
		if(cnt[u]!=-1)
			return cnt[u];
		long ans=acceptState[u]? 1 : 0;
		for(Entry<Character, Integer> e : SA.nxt[u].entrySet()){
			int v=e.getValue();
			ans+=dfs(v);
		}
		return cnt[u]=ans;
	}

	static class SuffixAutomaton {
		int [] link,len;
		TreeMap<Character, Integer> [] nxt;
		int lst, idx;

		SuffixAutomaton(char [] s){
			int n=s.length;
			link=new int [n<<1];
			len=new int [n<<1];
			nxt=new TreeMap [n<<1];
			nxt[0]=new TreeMap<Character, Integer>();
			for(char c : s)
				addLeter(c);
		}

		void addLeter(char c){
			int cur = ++idx;
			int p=lst;
			while(!nxt[p].containsKey(c)){
				nxt[p].put(c, cur);
				p=link[p];
			}
			int q=nxt[p].get(c);

			// a node containing an edge with character c stopped me and it is not the root
			if(q!=cur){
				if(len[q]==len[p]+1)
					link[cur]=q;
				else{
					int clone=++idx;
					len[clone]=len[p]+1;
					link[clone]=link[q];
					nxt[clone]=new TreeMap<Character, Integer>(nxt[q]);
					link[cur]=link[q]=clone;
					while(nxt[p].get(c)==q){
						nxt[p].put(c, clone);
						p=link[p];
					}
				}
			}
			len[cur]=len[lst]+1;
			nxt[cur]=new TreeMap<Character, Integer>();
			lst=cur;
		}

	}

	static class MyScanner {
		BufferedReader br;
		StringTokenizer st;
		public MyScanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}
		String next() {while (st == null || !st.hasMoreElements()) {
			try {st = new StringTokenizer(br.readLine());}
			catch (IOException e) {e.printStackTrace();}}
		return st.nextToken();}
		int nextInt() {return Integer.parseInt(next());}
		long nextLong() {return Long.parseLong(next());}
		double nextDouble() {return Double.parseDouble(next());}
		String nextLine(){String str = "";
		try {str = br.readLine();}
		catch (IOException e) {e.printStackTrace();}
		return str;}
	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.TreeMap;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author OmarYasser
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        Scanner in = new Scanner(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskD solver = new TaskD();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskD {
        public void solve(int testNumber, Scanner sc, PrintWriter out) {
            out.println(new SuffixAutomaton((sc.next() + "#").toCharArray()).solve());
        }

        class SuffixAutomaton {
            int[] link;
            int[] len;
            TreeMap<Character, Integer>[] next;
            int lst;
            int idx;
            long[] cnt;

            SuffixAutomaton(char[] s) {
                int n = s.length;
                link = new int[n << 1];
                len = new int[n << 1];
                next = new TreeMap[n << 1];
                cnt = new long[n << 1 << 1];
                Arrays.fill(cnt, -1);
                next[0] = new TreeMap<>();
                for (char c : s)
                    addLetter(c);
            }

            long solve() {
                long res = 0;
                for (int i = 1; i < idx; i++) {
                    res += 1l * (len[i] - len[link[i]]) * dp(i) * (dp(i) + 1) / 2;
                }
                return res;
            }

            long dp(int i) {
                if (i == idx)
                    return 1;
                if (cnt[i] != -1)
                    return cnt[i];
                long res = 0;
                for (int nxt : next[i].values())
                    res += dp(nxt);
                return cnt[i] = res;
            }

            void addLetter(char c) {
                int cur = ++idx, p = lst;
                while (!next[p].containsKey(c)) {
                    next[p].put(c, cur);
                    p = link[p];
                }

                int q = next[p].get(c);
                if (q != cur)
                    if (len[q] == len[p] + 1)
                        link[cur] = q;
                    else {
                        int clone = ++idx;
                        len[clone] = len[p] + 1;
                        link[clone] = link[q];
                        next[clone] = new TreeMap<>(next[q]);
                        link[cur] = link[q] = clone;
                        while (next[p].get(c) == q) {
                            next[p].put(c, clone);
                            p = link[p];
                        }
                    }
                len[cur] = len[lst] + 1;
                next[cur] = new TreeMap<>();
                lst = cur;
            }

        }

    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        public Scanner(InputStream s) {
            br = new BufferedReader(new InputStreamReader(s));
        }

        public Scanner(FileReader f) {
            br = new BufferedReader(f);
        }

        public String next() {
            while (st == null || !st.hasMoreTokens())
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (Exception e) {
                }
            return st.nextToken();
        }

    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

/**
 * @author Pavel Mavrin
 */
public class Z123D {

    private SuffixTree tree;
    private int k;
    private String ss;

    private void solve() throws IOException {
        ss = next();
        int[] s = new int[ss.length() + 1];
        for (int i = 0; i < ss.length(); i++) {
            s[i] = ss.charAt(i) - 'a' + 1;
        }
        tree = new SuffixTree(s);

//        print(tree.root, 0);
        size = new int[tree.vn];
        dfs(tree.root);
        res -= ss.length() + 1;
        out.println(res);
    }

    int[] size;

//    private void print(int v, int indent) {
//        String s = "";
//        for (int i = 0; i < indent; i++) {
//            s += " ";
//        }
//        for (int i = 0; i < SuffixTree.ALPHA_SIZE; i++) {
//            int u = tree.edge_next[v * SuffixTree.ALPHA_SIZE + i];
//            if (u > 0) {
//                System.out.println(s + ss.substring(
//                        tree.edge_st[v * SuffixTree.ALPHA_SIZE + i],
//                        tree.edge_st[v * SuffixTree.ALPHA_SIZE + i] + tree.edge_len[v * SuffixTree.ALPHA_SIZE + i]
//                ));
//                print(tree.edge_next[v * SuffixTree.ALPHA_SIZE + i], indent + 1);
//            }
//        }
//    }

    long res = 0;

    private void dfs(int v) {
        int dd = 0;
        for (int i = 0; i < SuffixTree.ALPHA_SIZE; i++) {
            int x = v * SuffixTree.ALPHA_SIZE + i;
            int len = tree.edge_len[x];
            int u = tree.edge_next[x];
            if (u > 0) {
                dfs(u);
                res += 1l * len * (size[u] * (size[u] + 1)) / 2;
                size[v] += size[u];
                dd++;
            }
        }
        if (dd == 0) {
            size[v] = 1;
        }
    }

    class SuffixTree {

        private static final int ALPHA_SIZE = 27;

        int s[], n, vn, root, suf[], dep[], size[];
        int[] edge_st, edge_len, edge_next;

        int newV(int d, int end) {
            assert (vn < suf.length);
            dep[vn] = d;
            size[vn] = end;
            return vn++;
        }

        int split(int v, int c, int i) {
            int a = v * ALPHA_SIZE + c;
            int u = newV(dep[v] + i, 0);
            int b = u * ALPHA_SIZE + s[edge_st[a] + i];
            edge_st[b] = edge_st[a] + i;
            edge_len[b] = edge_len[a] - i;
            edge_next[b] = edge_next[a];
            edge_len[a] = i;
            edge_next[a] = u;
            return u;
        }

        void create(int u, int c, int i) {
            int x = u * ALPHA_SIZE + c;
            edge_st[x] = i;
            edge_len[x] = n - i;
            edge_next[x] = newV(dep[u] + (n - i), 1);
        }

        public SuffixTree(int[] s) {
            this.s = s;
            this.n = s.length;
            int len = 1 + n * 2;
            suf = new int[len];
            dep = new int[len];
            size = new int[len];
            edge_len = new int[len * ALPHA_SIZE];
            edge_next = new int[len * ALPHA_SIZE];
            edge_st = new int[len * ALPHA_SIZE];

            vn = 0;
            root = newV(0, 0);

            int v = 0, cur_c = 0, cur_i = 0;
            for (int i = 0; i < n; i++) {
                if (cur_i > 0 && cur_i == edge_len[v * ALPHA_SIZE + cur_c]) {
                    v = edge_next[v * ALPHA_SIZE + cur_c];
                    cur_i = 0;
                }
                int c = s[i], last = -1;
                int t = edge_st[v * ALPHA_SIZE + cur_c];
                while (cur_i > 0 && s[t + cur_i] != c) {
                    int w = suf[v], u = split(v, cur_c, cur_i);
                    create(u, c, i);
                    if (last != -1)
                        suf[last] = u;
                    last = u;
                    if (v == 0) {
                        t++;
                        cur_i--;
                    }
                    int a;
                    while (cur_i > 0 && edge_len[a = w * ALPHA_SIZE + (cur_c = s[t])] <= cur_i) {
                        cur_i -= edge_len[a];
                        w = edge_next[a];
                        t += edge_len[a];
                    }
                    v = w;
                    if (cur_i == 0)
                        suf[last] = v;
                }
                if (cur_i > 0) {
                    cur_i++;
                } else {
                    cur_i = 1;
                    cur_c = c;
                    while (edge_len[v * ALPHA_SIZE + c] < cur_i) {
                        create(v, c, i);
                        if (v > 0)
                            v = suf[v];
                        else
                            cur_i = 0;
                    }
                }
            }
        }
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static void main(String[] args) throws IOException {
        new Z123D().run();
    }

    private void run() throws IOException {
        solve();
        out.close();
    }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @author Pavel Mavrin
 */
public class Z123D {

    private String ss;
    private SuffixAutomaton aut;

    private void solve() throws IOException {
        ss = next();
        ss += (char)('z' + 1);
        aut = new SuffixAutomaton(ss);
        size = new int[aut.n];
        p = new int[aut.n];
        cur = aut.n - 1;
        z = new boolean[aut.n];
        dfs(aut.root);
        size2 = new int[aut.n];
        size2[aut.root] = 1;
        for (int v = 0; v < aut.n; v++) {
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    size2[u] += size2[v];
                    res += 1l * size2[v] * size[u] * (size[u] + 1) / 2;
                }
            }
        }
        out.println(res - ss.length());
    }

    int[] size;
    int[] size2;
    int[] p;
    int cur;
    boolean[] z;

    long res = 0;

    private void dfs(int v) {
        if (z[v]) return;
        z[v] = true;
        if (v == aut.last) {
            size[v] = 1;
        } else {
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    dfs(u);
                    size[v] += size[u];
                }
            }
        }
        p[cur--] = v;
    }

    /**
     * Author: Sergey Kopeliovich (Burunduk30@gmail.com)
     * (translated from C++ by Pavel Mavrin)
     */

    class SuffixAutomaton {

        public static final int ALPHA_SIZE = 27;
        public int root, last, n;
        public final int len[], suf[], next[];

        public SuffixAutomaton(String s) {
            len = new int[s.length() + 2];
            suf = new int[s.length() + 2];
            //compressed 2d array. next[i][j] -> next[i * ALPHA_SIZE + j];
            next = new int[(s.length() + 2) * ALPHA_SIZE];
            for (int i = 0; i < ALPHA_SIZE; i++)
                next[i] = 1;
            n = 1;
            root = last = newV(0, 0);
            for (int i = 0; i < s.length(); i++) {
                int ch = s.charAt(i) - 'a';
                int R, Q, P = last;
                last = newV(len[last] + 1, 0);
                while (next[P * ALPHA_SIZE + ch] == 0) {
                    next[P * ALPHA_SIZE + ch] = last;
                    P = suf[P];
                }
                if (P == 0)
                    suf[last] = 1;
                else if (len[Q = next[P * ALPHA_SIZE + ch]] == len[P] + 1)
                    suf[last] = Q;
                else {
                    R = newV(len[P] + 1, suf[Q]);
                    suf[last] = suf[Q] = R;
                    System.arraycopy(next, Q * ALPHA_SIZE, next, R * ALPHA_SIZE, ALPHA_SIZE);
                    while (P > 0 && next[P * ALPHA_SIZE + ch] == Q) {
                        next[P * ALPHA_SIZE + ch] = R;
                        P = suf[P];
                    }
                }
            }
        }

        private int newV(int l, int _suf) {
            if ((n >= len.length)) throw new AssertionError();
            for (int i = 0; i < ALPHA_SIZE; i++) {
                next[n * ALPHA_SIZE + i] = 0;
            }
            len[n] = l;
            suf[n] = _suf;
            return n++;
        }
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static void main(String[] args) throws IOException {
        new Z123D().run();
    }

    private void run() throws IOException {
        solve();
        out.close();
    }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;

/**
 * @author Pavel Mavrin
 */
public class Z123D {

    private SuffixTree tree;
    private int k;
    private String ss;

    private void solve() throws IOException {
        ss = next();
        int[] s = new int[ss.length() + 1];
        for (int i = 0; i < ss.length(); i++) {
            s[i] = ss.charAt(i) - 'a' + 1;
        }
        tree = new SuffixTree(s);

//        print(tree.root, 0);
        size = new int[tree.vn];
        dfs(tree.root);
        res -= ss.length() + 1;
        out.println(res);
    }

    int[] size;

//    private void print(int v, int indent) {
//        String s = "";
//        for (int i = 0; i < indent; i++) {
//            s += " ";
//        }
//        for (int i = 0; i < SuffixTree.ALPHA_SIZE; i++) {
//            int u = tree.edge_next[v * SuffixTree.ALPHA_SIZE + i];
//            if (u > 0) {
//                System.out.println(s + ss.substring(
//                        tree.edge_st[v * SuffixTree.ALPHA_SIZE + i],
//                        tree.edge_st[v * SuffixTree.ALPHA_SIZE + i] + tree.edge_len[v * SuffixTree.ALPHA_SIZE + i]
//                ));
//                print(tree.edge_next[v * SuffixTree.ALPHA_SIZE + i], indent + 1);
//            }
//        }
//    }

    long res = 0;

    private void dfs(int v) {
        int dd = 0;
        for (int i = 0; i < SuffixTree.ALPHA_SIZE; i++) {
            int x = v * SuffixTree.ALPHA_SIZE + i;
            int len = tree.edge_len[x];
            int u = tree.edge_next[x];
            if (u > 0) {
                dfs(u);
                res += 1l * len * size[u] * (size[u] + 1) / 2;
                size[v] += size[u];
                dd++;
            }
        }
        if (dd == 0) {
            size[v] = 1;
        }
    }

    class SuffixTree {

        private static final int ALPHA_SIZE = 27;

        int s[], n, vn, root, suf[], dep[], size[];
        int[] edge_st, edge_len, edge_next;

        int newV(int d, int end) {
            assert (vn < suf.length);
            dep[vn] = d;
            size[vn] = end;
            return vn++;
        }

        int split(int v, int c, int i) {
            int a = v * ALPHA_SIZE + c;
            int u = newV(dep[v] + i, 0);
            int b = u * ALPHA_SIZE + s[edge_st[a] + i];
            edge_st[b] = edge_st[a] + i;
            edge_len[b] = edge_len[a] - i;
            edge_next[b] = edge_next[a];
            edge_len[a] = i;
            edge_next[a] = u;
            return u;
        }

        void create(int u, int c, int i) {
            int x = u * ALPHA_SIZE + c;
            edge_st[x] = i;
            edge_len[x] = n - i;
            edge_next[x] = newV(dep[u] + (n - i), 1);
        }

        public SuffixTree(int[] s) {
            this.s = s;
            this.n = s.length;
            int len = 1 + n * 2;
            suf = new int[len];
            dep = new int[len];
            size = new int[len];
            edge_len = new int[len * ALPHA_SIZE];
            edge_next = new int[len * ALPHA_SIZE];
            edge_st = new int[len * ALPHA_SIZE];

            vn = 0;
            root = newV(0, 0);

            int v = 0, cur_c = 0, cur_i = 0;
            for (int i = 0; i < n; i++) {
                if (cur_i > 0 && cur_i == edge_len[v * ALPHA_SIZE + cur_c]) {
                    v = edge_next[v * ALPHA_SIZE + cur_c];
                    cur_i = 0;
                }
                int c = s[i], last = -1;
                int t = edge_st[v * ALPHA_SIZE + cur_c];
                while (cur_i > 0 && s[t + cur_i] != c) {
                    int w = suf[v], u = split(v, cur_c, cur_i);
                    create(u, c, i);
                    if (last != -1)
                        suf[last] = u;
                    last = u;
                    if (v == 0) {
                        t++;
                        cur_i--;
                    }
                    int a;
                    while (cur_i > 0 && edge_len[a = w * ALPHA_SIZE + (cur_c = s[t])] <= cur_i) {
                        cur_i -= edge_len[a];
                        w = edge_next[a];
                        t += edge_len[a];
                    }
                    v = w;
                    if (cur_i == 0)
                        suf[last] = v;
                }
                if (cur_i > 0) {
                    cur_i++;
                } else {
                    cur_i = 1;
                    cur_c = c;
                    while (edge_len[v * ALPHA_SIZE + c] < cur_i) {
                        create(v, c, i);
                        if (v > 0)
                            v = suf[v];
                        else
                            cur_i = 0;
                    }
                }
            }
        }
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static void main(String[] args) throws IOException {
        new Z123D().run();
    }

    private void run() throws IOException {
        solve();
        out.close();
    }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @author Pavel Mavrin
 */
public class Z123D {

    private String ss;
    private SuffixAutomaton aut;

    private void solve() throws IOException {
        ss = next();
        ss += (char)('z' + 1);
        aut = new SuffixAutomaton(ss);
//        for (int i= 1; i < aut.n; i++) {
//            for (int j = 0; j < aut.ALPHA_SIZE; j++) {
//                int x = aut.next[i * aut.ALPHA_SIZE + j];
//                if (x != 0) {
//                    System.out.println(i + " - " + x + " " + (char)('a'+j));
//                }
//            }
//        }
        size = new int[aut.n];
        p = new int[aut.n];
        cur = aut.n - 1;
        z = new boolean[aut.n];
        dfs(aut.root);
        size2 = new int[aut.n];
        size2[aut.root] = 1;
        for (int vv = 0; vv < aut.n; vv++) {
            int v = p[vv];
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    size2[u] += size2[v];
                    res += 1l * size2[v] * size[u] * (size[u] + 1) / 2;
                }
            }
        }
//        System.out.println(Arrays.toString(p));
//        System.out.println(Arrays.toString(size));
//        System.out.println(Arrays.toString(size2));
        out.println(res - ss.length());
    }

    int[] size;
    int[] size2;
    int[] p;
    int cur;
    boolean[] z;

    long res = 0;

    private void dfs(int v) {
        if (z[v]) return;
        z[v] = true;
        if (v == aut.last) {
            size[v] = 1;
        } else {
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    dfs(u);
                    size[v] += size[u];
                }
            }
        }
        p[cur--] = v;
    }

    /**
     * Author: Sergey Kopeliovich (Burunduk30@gmail.com)
     * (translated from C++ by Pavel Mavrin)
     */

    class SuffixAutomaton {

        public static final int ALPHA_SIZE = 27;
        public int root, last, n;
        public final int len[], suf[], next[];

        public SuffixAutomaton(String s) {
            len = new int[2 * s.length() + 2];
            suf = new int[2 * s.length() + 2];
            //compressed 2d array. next[i][j] -> next[i * ALPHA_SIZE + j];
            next = new int[(2 * s.length() + 2) * ALPHA_SIZE];
            for (int i = 0; i < ALPHA_SIZE; i++)
                next[i] = 1;
            n = 1;
            root = last = newV(0, 0);
            for (int i = 0; i < s.length(); i++) {
                int ch = s.charAt(i) - 'a';
                int R, Q, P = last;
                last = newV(len[last] + 1, 0);
                while (next[P * ALPHA_SIZE + ch] == 0) {
                    next[P * ALPHA_SIZE + ch] = last;
                    P = suf[P];
                }
                if (P == 0)
                    suf[last] = 1;
                else if (len[Q = next[P * ALPHA_SIZE + ch]] == len[P] + 1)
                    suf[last] = Q;
                else {
                    R = newV(len[P] + 1, suf[Q]);
                    suf[last] = suf[Q] = R;
                    System.arraycopy(next, Q * ALPHA_SIZE, next, R * ALPHA_SIZE, ALPHA_SIZE);
                    while (P > 0 && next[P * ALPHA_SIZE + ch] == Q) {
                        next[P * ALPHA_SIZE + ch] = R;
                        P = suf[P];
                    }
                }
            }
        }

        private int newV(int l, int _suf) {
            if ((n >= len.length)) throw new AssertionError();
            for (int i = 0; i < ALPHA_SIZE; i++) {
                next[n * ALPHA_SIZE + i] = 0;
            }
            len[n] = l;
            suf[n] = _suf;
            return n++;
        }
    }

    //eqkrqe
    // e 3 6+5+4+3+2+1 21

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static void main(String[] args) throws IOException {
        new Z123D().run();
    }

    private void run() throws IOException {
        solve();
        out.close();
    }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.StringTokenizer;

/**
 * @author Pavel Mavrin
 */
public class Z123D {

    private String ss;
    private SuffixAutomaton aut;

    private void solve() throws IOException {
        ss = next();
        ss += (char)('z' + 1);
        aut = new SuffixAutomaton(ss);
        size = new int[aut.n];
        p = new int[aut.n];
        cur = aut.n - 1;
        z = new boolean[aut.n];
        dfs(aut.root);
        size2 = new int[aut.n];
        size2[aut.root] = 1;
        for (int v = 0; v < aut.n; v++) {
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    size2[u] += size2[v];
                    res += 1l * size2[v] * size[u] * (size[u] + 1) / 2;
                }
            }
        }
        out.println(res - ss.length());
    }

    int[] size;
    int[] size2;
    int[] p;
    int cur;
    boolean[] z;

    long res = 0;

    private void dfs(int v) {
        if (z[v]) return;
        z[v] = true;
        if (v == aut.last) {
            size[v] = 1;
        } else {
            for (int i = 0; i < SuffixAutomaton.ALPHA_SIZE; i++) {
                int x = v * SuffixAutomaton.ALPHA_SIZE + i;
                int u = aut.next[x];
                if (u > 0) {
                    dfs(u);
                    size[v] += size[u];
                }
            }
        }
        p[cur--] = v;
    }

    /**
     * Author: Sergey Kopeliovich (Burunduk30@gmail.com)
     * (translated from C++ by Pavel Mavrin)
     */

    class SuffixAutomaton {

        public static final int ALPHA_SIZE = 27;
        public int root, last, n;
        public final int len[], suf[], next[];

        public SuffixAutomaton(String s) {
            len = new int[2 * s.length() + 2];
            suf = new int[2 * s.length() + 2];
            //compressed 2d array. next[i][j] -> next[i * ALPHA_SIZE + j];
            next = new int[(2 * s.length() + 2) * ALPHA_SIZE];
            for (int i = 0; i < ALPHA_SIZE; i++)
                next[i] = 1;
            n = 1;
            root = last = newV(0, 0);
            for (int i = 0; i < s.length(); i++) {
                int ch = s.charAt(i) - 'a';
                int R, Q, P = last;
                last = newV(len[last] + 1, 0);
                while (next[P * ALPHA_SIZE + ch] == 0) {
                    next[P * ALPHA_SIZE + ch] = last;
                    P = suf[P];
                }
                if (P == 0)
                    suf[last] = 1;
                else if (len[Q = next[P * ALPHA_SIZE + ch]] == len[P] + 1)
                    suf[last] = Q;
                else {
                    R = newV(len[P] + 1, suf[Q]);
                    suf[last] = suf[Q] = R;
                    System.arraycopy(next, Q * ALPHA_SIZE, next, R * ALPHA_SIZE, ALPHA_SIZE);
                    while (P > 0 && next[P * ALPHA_SIZE + ch] == Q) {
                        next[P * ALPHA_SIZE + ch] = R;
                        P = suf[P];
                    }
                }
            }
        }

        private int newV(int l, int _suf) {
            if ((n >= len.length)) throw new AssertionError();
            for (int i = 0; i < ALPHA_SIZE; i++) {
                next[n * ALPHA_SIZE + i] = 0;
            }
            len[n] = l;
            suf[n] = _suf;
            return n++;
        }
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

    String next() throws IOException {
        while (st == null || !st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }

    int nextInt() throws IOException {
        return Integer.parseInt(next());
    }

    public static void main(String[] args) throws IOException {
        new Z123D().run();
    }

    private void run() throws IOException {
        solve();
        out.close();
    }

}


import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

/**
 * Created by dalt on 2018/4/2.
 */
public class CF123D {
    public static final int MOD = (int) (1e9 + 7);
    public static BlockReader input;
    public static PrintStream output;

    public static void main(String[] args) throws FileNotFoundException {

        init();

        solve();

        output.flush();
    }

    public static void init() throws FileNotFoundException {
        if (System.getProperty("ONLINE_JUDGE") == null) {
            input = new BlockReader(new FileInputStream("D:\\DataBase\\TESTCASE\\codeforces\\CF123D.in"));
            output = System.out;
        } else {
            input = new BlockReader(System.in);
            output = new PrintStream(new BufferedOutputStream(System.out), false);
        }
    }

    public static void solve() {
        char[] data = new char[100000];
        int n = input.nextBlock(data, 0);

        SAM sam = new SAM();
        for (int i = 0; i < n; i++) {
            sam.build(data[i]);
        }

        long sum = 0;
        SAM.Node[] nodes = sam.nodeList.toArray(new SAM.Node[0]);
        Arrays.sort(nodes, new Comparator<SAM.Node>() {
            @Override
            public int compare(SAM.Node o1, SAM.Node o2) {
                return o2.maxlen - o1.maxlen;
            }
        });

        for (int i = 0, until = nodes.length; i < until; i++) {
            SAM.Node node = nodes[i];
            node.fail.cnt += node.cnt;
            sum += (long) node.cnt * (node.cnt + 1) / 2 * (node.maxlen - node.fail.maxlen);
        }

        output.println(sum);
    }

    public static class SAM {
        Node root;
        Node buildLast;
        Node matchLast;
        List<Node> nodeList = new ArrayList<>();

        public SAM() {
            buildLast = matchLast = root = new Node();
        }

        public void build(char c) {
            int index = c - 'a';
            Node now = new Node();
            now.cnt = 1;
            now.maxlen = buildLast.maxlen + 1;

            Node trace = replace(buildLast, now, null, index);
            if (trace == null) {
                now.fail = root;
            } else {
                Node q = trace.nodes[index];
                if (q.maxlen == trace.maxlen + 1) {
                    now.fail = q;
                } else {
                    Node clone = new Node(q);
                    clone.maxlen = trace.maxlen + 1;
                    q.fail = now.fail = clone;
                    clone.cnt = 0;
                    replace(trace, clone, q, index);
                    nodeList.add(clone);
                }
            }

            buildLast = now;
            nodeList.add(now);
        }

        public static Node replace(Node start, Node newNode, Node oldNode, int index) {
            while (start != null && start.nodes[index] == oldNode) {
                start.nodes[index] = newNode;
                start = start.fail;
            }
            return start;
        }

        public static class Node {
            Node[] nodes = new Node[26];
            Node fail;
            int maxlen;
            int cnt;

            public Node() {
            }

            public Node(Node other) {
                for (int i = 0; i < 26; i++) {
                    nodes[i] = other.nodes[i];
                }
                fail = other.fail;
                maxlen = other.maxlen;
            }
        }
    }

    public static class BlockReader {
        static final int EOF = -1;
        InputStream is;
        byte[] dBuf;
        int dPos, dSize, next;
        StringBuilder builder = new StringBuilder();

        public BlockReader(InputStream is) {
            this(is, 4096);
        }

        public BlockReader(InputStream is, int bufSize) {
            this.is = is;
            dBuf = new byte[bufSize];
            next = nextByte();
        }

        public int nextByte() {
            while (dPos >= dSize) {
                if (dSize == -1) {
                    return EOF;
                }
                dPos = 0;
                try {
                    dSize = is.read(dBuf);
                } catch (Exception e) {
                }
            }
            return dBuf[dPos++];
        }

        public String nextBlock() {
            builder.setLength(0);
            skipBlank();
            while (next != EOF && !Character.isWhitespace(next)) {
                builder.append((char) next);
                next = nextByte();
            }
            return builder.toString();
        }

        public void skipBlank() {
            while (Character.isWhitespace(next)) {
                next = nextByte();
            }
        }

        public int nextInteger() {
            skipBlank();
            int ret = 0;
            boolean rev = false;
            if (next == '+' || next == '-') {
                rev = next == '-';
                next = nextByte();
            }
            while (next >= '0' && next <= '9') {
                ret = (ret << 3) + (ret << 1) + next - '0';
                next = nextByte();
            }
            return rev ? -ret : ret;
        }

        public long nextLong() {
            skipBlank();
            long ret = 0;
            boolean rev = false;
            if (next == '+' || next == '-') {
                rev = next == '-';
                next = nextByte();
            }
            while (next >= '0' && next <= '9') {
                ret = (ret << 3) + (ret << 1) + next - '0';
                next = nextByte();
            }
            return rev ? -ret : ret;
        }

        public int nextBlock(char[] data, int offset) {
            skipBlank();
            int index = offset;
            int bound = data.length;
            while (next != EOF && index < bound && !Character.isWhitespace(next)) {
                data[index++] = (char) next;
                next = nextByte();
            }
            return index - offset;
        }

        public boolean hasMore() {
            skipBlank();
            return next != EOF;
        }
    }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Arrays;
import java.util.Map.Entry;

public class String_123D {
	static SuffixAutomaton sa;

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		sb.append(sc.next());
		int n = sb.length();
		sa = new SuffixAutomaton(sb.toString().toCharArray());
		accept = new boolean[n << 1];
		int cur = sa.lst;
		accept[cur] = true;
		while (cur != 0) {
			cur = sa.link[cur];
			accept[cur] = true;
		}
		memo = new long[n << 1];
		Arrays.fill(memo, -1);
		solve(0);
		long ans = 0;
		for (int i = 0; i <= sa.idx; i++) {
			long min = sa.len[sa.link[i]];
			long max = sa.len[i];
			long dif = max - min;
			long distinct = solve(i);
			long x = 1l * distinct * (distinct + 1) / 2;
			ans += (1l * dif * x);
		}
		System.out.println(ans);
	}

	static long[] memo;
	static boolean[] accept;

	static long solve(int idx) {
		if (memo[idx] != -1)
			return memo[idx];
		long ret = 0;
		if (accept[idx])
			ret++;
		for (Entry<Character, Integer> entry : sa.next[idx].entrySet()) {
			int nxtNode = entry.getValue();
			ret += solve(nxtNode);
		}
		return memo[idx] = ret;
	}

	static class SuffixAutomaton {
		int[] link, len;
		TreeMap<Character, Integer>[] next;
		int lst, idx;

		@SuppressWarnings("unchecked")
		public SuffixAutomaton(char[] s) {
			int n = s.length;
			link = new int[n << 1];
			len = new int[n << 1];
			next = new TreeMap[n << 1];
			next[0] = new TreeMap<>();
			for (char c : s)
				addLetter(c);

		}

		private void addLetter(char c) {
			int cur = ++idx, p = lst;
			while (!next[p].containsKey(c)) {
				next[p].put(c, cur);
				p = link[p];
			}
			int q = next[p].get(c);
			if (q != cur) // If I stopped failing before reaching the root
				if (len[q] == len[p] + 1)
					link[cur] = q;
				else {
					int clone = ++idx;
					len[clone] = len[p + 1];
					link[clone] = link[q];
					next[clone] = new TreeMap<>(next[q]);
					link[cur] = link[q] = clone;
					while (next[p].get(c) == p) {
						next[p].put(c, clone);
						p = link[p];
					}
				}
			len[cur] = len[lst] + 1;
			next[cur] = new TreeMap<>();
			lst = cur;
		}

	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			return Double.parseDouble(next());
		}

		public boolean ready() throws IOException {
			return br.ready();
		}
	}
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Arrays;
import java.util.Map.Entry;

public class String_123D {
	static SuffixAutomaton sa;

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		sb.append(sc.next());
		int n = sb.length();
		sa = new SuffixAutomaton(sb.toString().toCharArray());
		accept = new boolean[n << 1];
		int cur = sa.lst;
		accept[cur] = true;
		while (cur != 0) {
			cur = sa.link[cur];
			accept[cur] = true;
		}
		memo = new long[n << 1];
		Arrays.fill(memo, -1);
		long ans = 0;
		for (int i = 0; i <= sa.idx; i++) {
			long min = sa.len[sa.link[i]];
			long max = sa.len[i];
			long dif = max - min;
			long distinct = solve(i);
			long x = 1l * distinct * (distinct + 1) / 2;
			ans += (1l * dif * x);
		}
		System.out.println(ans);
	}

	static long[] memo;
	static boolean[] accept;

	static long solve(int idx) {
		if (memo[idx] != -1)
			return memo[idx];
		long ret = 0;
		if (accept[idx])
			ret++;
		for (Entry<Character, Integer> entry : sa.next[idx].entrySet()) {
			int nxtNode = entry.getValue();
			ret += solve(nxtNode);
		}
		return memo[idx] = ret;
	}

	static class SuffixAutomaton {
		int[] link, len;
		TreeMap<Character, Integer>[] next;
		int lst, idx;

		@SuppressWarnings("unchecked")
		public SuffixAutomaton(char[] s) {
			int n = s.length;
			link = new int[n << 1];
			len = new int[n << 1];
			next = new TreeMap[n << 1];
			next[0] = new TreeMap<>();
			for (char c : s)
				addLetter(c);

		}

		private void addLetter(char c) {
			int cur = ++idx, p = lst;
			while (!next[p].containsKey(c)) {
				next[p].put(c, cur);
				p = link[p];
			}
			int q = next[p].get(c);
			if (q != cur) // If I stopped failing before reaching the root
				if (len[q] == len[p] + 1)
					link[cur] = q;
				else {
					int clone = ++idx;
					len[clone] = len[p] + 1;
					link[clone] = link[q];
					next[clone] = new TreeMap<>(next[q]);
					link[cur] = link[q] = clone;
					while (next[p].get(c) == q) {
						next[p].put(c, clone);
						p = link[p];
					}
				}
			len[cur] = len[lst] + 1;
			next[cur] = new TreeMap<>();
			lst = cur;
		}

	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			return Double.parseDouble(next());
		}

		public boolean ready() throws IOException {
			return br.ready();
		}
	}
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.Arrays;
import java.util.Map.Entry;

public class String_123D {
	static SuffixAutomaton sa;

	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		StringBuilder sb = new StringBuilder();
		sb.append(sc.next());
		int n = sb.length();
		sa = new SuffixAutomaton(sb.toString().toCharArray());
		accept = new boolean[n << 1];
		int cur = sa.lst;
		accept[cur] = true;
		while (cur != 0) {
			cur = sa.link[cur];
			accept[cur] = true;
		}
		memo = new int[n << 1];
		Arrays.fill(memo, -1);
		solve(0);
		long ans = 0;
		for (int i = 0; i <= sa.idx; i++) {
			long min = sa.len[sa.link[i]];
			long max = sa.len[i];
			long dif = max - min;
			long distinct = solve(i);
			long x = 1l * distinct * (distinct + 1) / 2;
			ans += (1l * dif * x);
		}
		System.out.println(ans);
	}

	static int[] memo;
	static boolean[] accept;

	static int solve(int idx) {
		if (memo[idx] != -1)
			return memo[idx];
		int ret = 0;
		if (accept[idx])
			ret++;
		for (Entry<Character, Integer> entry : sa.next[idx].entrySet()) {
			int nxtNode = entry.getValue();
			ret += solve(nxtNode);
		}
		return memo[idx] = ret;
	}

	static class SuffixAutomaton {
		int[] link, len;
		TreeMap<Character, Integer>[] next;
		int lst, idx;

		@SuppressWarnings("unchecked")
		public SuffixAutomaton(char[] s) {
			int n = s.length;
			link = new int[n << 1];
			len = new int[n << 1];
			next = new TreeMap[n << 1];
			next[0] = new TreeMap<>();
			for (char c : s)
				addLetter(c);

		}

		private void addLetter(char c) {
			int cur = ++idx, p = lst;
			while (!next[p].containsKey(c)) {
				next[p].put(c, cur);
				p = link[p];
			}
			int q = next[p].get(c);
			if (q != cur) // If I stopped failing before reaching the root
				if (len[q] == len[p] + 1)
					link[cur] = q;
				else {
					int clone = ++idx;
					len[clone] = len[p + 1];
					link[clone] = link[q];
					next[clone] = new TreeMap<>(next[q]);
					link[cur] = link[q] = clone;
					while (next[p].get(c) == p) {
						next[p].put(c, clone);
						p = link[p];
					}
				}
			len[cur] = len[lst] + 1;
			next[cur] = new TreeMap<>();
			lst = cur;
		}

	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

		public Scanner(String s) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(new File(s)));
		}

		public String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		public int nextInt() throws IOException {
			return Integer.parseInt(next());
		}

		public long nextLong() throws IOException {
			return Long.parseLong(next());
		}

		public String nextLine() throws IOException {
			return br.readLine();
		}

		public double nextDouble() throws IOException {
			return Double.parseDouble(next());
		}

		public boolean ready() throws IOException {
			return br.ready();
		}
	}
}


//Created by Aminul on 9/3/2019.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Stack;

import static java.lang.Math.max;

public class CF123D_2 {
    public static void main(String[] args) throws Exception {
        //Scanner in = new Scanner(System.in);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);
        char[] s = br.readLine().toCharArray();
        int n = s.length;
        int sa[] = suffixArray(s);
        final int lcp[] = lcp(sa, s);
        long ans = 0;
        SegTree segTree = new SegTree(n + 1);
        for (int i = n - 1; i >= 0; i--) {
            int len = n - sa[i];
            ans += segTree.query(1, len) + len;
            segTree.clearRange(lcp[i] + 1, n);
            segTree.update(1, lcp[i], 1);
        }
        pw.println(ans);
        pw.close();
    }

    static int brute(int n, int sa[], int lcp[]) {
        int ans = 0;
        for (int i = 0; i < n; i++) {
            int len = n - sa[i];
            for (int j = 1; j <= len; j++) {
                ans++;
                for (int k = i + 1; k < n; k++) {
                    if (lcp[k] < j) break;
                    ans++;
                }
            }
        }
        return ans;
    }

    static int[] suffixArray(char[] S) {
        int n = S.length;
        Integer ord[] = new Integer[n];
        for (int i = 0; i < n; i++) ord[i] = n - 1 - i;
        Arrays.sort(ord, (a, b) -> Character.compare(S[a], S[b]));
        int order[] = new int[n];
        for (int i = 0; i < n; i++) order[i] = ord[i];
        //Arrays.sort(order, new Comparator<Integer>() {public int compare(Integer o1, Integer o2) { return S[o1] - S[o2]; }});
        int[] sa = new int[n];
        int[] classes = new int[n];
        for (int i = 0; i < n; i++) {
            sa[i] = order[i];
            classes[i] = S[i];
        }
        for (int len = 1; len < n; len <<= 1) {
            int[] c = classes.clone();
            for (int i = 0; i < n; i++) {
                classes[sa[i]] = i > 0 && c[sa[i - 1]] == c[sa[i]] && sa[i - 1] + len < n
                        && c[sa[i - 1] + (len >> 1)] == c[sa[i] + (len >> 1)] ? classes[sa[i - 1]] : i;
            }
            int[] cnt = new int[n];
            for (int i = 0; i < n; i++) {
                cnt[i] = i;
            }
            int[] s = sa.clone();
            for (int i = 0; i < n; i++) {
                int s1 = s[i] - len;
                if (s1 >= 0) {
                    sa[cnt[classes[s1]]++] = s1;
                }
            }
        }
        return sa;
    }

    static int[] lcp(int[] sa, char[] s) {
        int n = sa.length;
        int[] rank = new int[n];
        for (int i = 0; i < n; i++)
            rank[sa[i]] = i;
        int[] lcp = new int[n];

        for (int i = 0, h = 0; i < n; i++) {
            if (rank[i] < n - 1) {
                for (int j = sa[rank[i] + 1]; max(i, j) + h < s.length
                        && s[i + h] == s[j + h]; ++h)
                    ;
                lcp[rank[i] + 1] = h;
                if (h > 0)
                    --h;
            }
        }
        return lcp;
    }

    static void debug(Object... obj) {
        System.err.println(Arrays.deepToString(obj));
    }

    static class SegTree {
        Node root;
        int n;

        SegTree(int N) {
            n = N;
            root = new Node();
        }

        void pushDown(Node node, int s, int m, int e) {
            if (node.lazy == 0) return;
            if (node.left != null) {
                node.left.value += (m - s + 1) * node.lazy;
                node.left.lazy += node.lazy;
            }
            if (node.right != null) {
                node.right.value += (e - m) * node.lazy;
                node.right.lazy += node.lazy;
            }
            node.lazy = 0;
        }

        void update(int l, int r, int v) {
            update(root, 1, n, l, r, v);
        }

        void update(Node node, int s, int e, int a, int b, int value) {
            if (s > e || s > b || e < a) return;
            if (s >= a && e <= b) {
                node.lazy += value;
                node.value += (e - s + 1) * value;
                return;
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            update(node.left, s, m, a, b, value);
            update(node.right, m + 1, e, a, b, value);
            node.value = node.left.value + node.right.value;
        }

        void clearRange(int l, int r) {
            root = clearRange(root, 1, n, l, r);
        }

        Node clearRange(Node node, int s, int e, int a, int b) {
            if (s > e || s > b || e < a) return node;
            if (s >= a && e <= b) {
                return new Node();
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            node.left = clearRange(node.left, s, m, a, b);
            node.right = clearRange(node.right, m + 1, e, a, b);
            node.value = node.left.value + node.right.value;
            return node;
        }

        long query(int l, int r) {
            return query(root, 1, n, l, r);
        }

        long query(Node node, int s, int e, int a, int b) {
            if (s > e || s > b || e < a) return 0;
            if (s >= a && e <= b) {
                return node.value;
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            return query(node.left, s, m, a, b) + query(node.right, m + 1, e, a, b);
        }

        static class Node {
            Node left, right;
            long value, lazy;

            Node() {
            }

            Node(int v) {
                value = v;
            }

            @Override
            public String toString() {
                return "[" + value + ", " + lazy + "]";
            }
        }
    }
}


//Created by Aminul on 9/3/2019.

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Stack;

import static java.lang.Math.max;

public class CF123D_2 {
    public static void main(String[] args) throws Exception {
        //Scanner in = new Scanner(System.in);
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter pw = new PrintWriter(System.out);
        char[] s = br.readLine().toCharArray();
        int n = s.length;
        int sa[] = suffixArray(s);
        final int lcp[] = lcp(sa, s);
        long ans = 0;
        SegTree segTree = new SegTree(n + 1);
        for (int i = n - 1; i >= 0; i--) {
            int len = n - sa[i];
            ans += segTree.query(1, len) + len;
            segTree.clearRange(lcp[i] + 1, n);
            segTree.update(1, lcp[i], 1);
        }
        pw.println(ans);
        pw.close();
    }

    static int brute(int n, int sa[], int lcp[]) {
        int ans = 0;
        for (int i = 0; i < n; i++) {
            int len = n - sa[i];
            for (int j = 1; j <= len; j++) {
                ans++;
                for (int k = i + 1; k < n; k++) {
                    if (lcp[k] < j) break;
                    ans++;
                }
            }
        }
        return ans;
    }

    static int[] suffixArray(char[] S) {
        int n = S.length;
        Integer ord[] = new Integer[n];
        for (int i = 0; i < n; i++) ord[i] = n - 1 - i;
        Arrays.sort(ord, (a, b) -> Character.compare(S[a], S[b]));
        int order[] = new int[n];
        for (int i = 0; i < n; i++) order[i] = ord[i];
        //Arrays.sort(order, new Comparator<Integer>() {public int compare(Integer o1, Integer o2) { return S[o1] - S[o2]; }});
        int[] sa = new int[n];
        int[] classes = new int[n];
        for (int i = 0; i < n; i++) {
            sa[i] = order[i];
            classes[i] = S[i];
        }
        for (int len = 1; len < n; len <<= 1) {
            int[] c = classes.clone();
            for (int i = 0; i < n; i++) {
                classes[sa[i]] = i > 0 && c[sa[i - 1]] == c[sa[i]] && sa[i - 1] + len < n
                        && c[sa[i - 1] + (len >> 1)] == c[sa[i] + (len >> 1)] ? classes[sa[i - 1]] : i;
            }
            int[] cnt = new int[n];
            for (int i = 0; i < n; i++) {
                cnt[i] = i;
            }
            int[] s = sa.clone();
            for (int i = 0; i < n; i++) {
                int s1 = s[i] - len;
                if (s1 >= 0) {
                    sa[cnt[classes[s1]]++] = s1;
                }
            }
        }
        return sa;
    }

    static int[] lcp(int[] sa, char[] s) {
        int n = sa.length;
        int[] rank = new int[n];
        for (int i = 0; i < n; i++)
            rank[sa[i]] = i;
        int[] lcp = new int[n];

        for (int i = 0, h = 0; i < n; i++) {
            if (rank[i] < n - 1) {
                for (int j = sa[rank[i] + 1]; max(i, j) + h < s.length
                        && s[i + h] == s[j + h]; ++h)
                    ;
                lcp[rank[i] + 1] = h;
                if (h > 0)
                    --h;
            }
        }
        return lcp;
    }

    static void debug(Object... obj) {
        System.err.println(Arrays.deepToString(obj));
    }

    static class SegTree {
        Node root;
        int n;

        SegTree(int N) {
            n = N;
            root = new Node();
        }

        void pushDown(Node node, int s, int m, int e) {
            if (node.lazy == 0) return;
            if (node.left != null) {
                node.left.value += (m - s + 1) * node.lazy;
                node.left.lazy += node.lazy;
            }
            if (node.right != null) {
                node.right.value += (e - m) * node.lazy;
                node.right.lazy += node.lazy;
            }
            node.lazy = 0;
        }

        void update(int l, int r, int v) {
            update(root, 1, n, l, r, v);
        }

        void update(Node node, int s, int e, int a, int b, int value) {
            if (s > e || s > b || e < a) return;
            if (s >= a && e <= b) {
                node.lazy += value;
                node.value += (e - s + 1) * value;
                return;
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            update(node.left, s, m, a, b, value);
            update(node.right, m + 1, e, a, b, value);
            node.value = node.left.value + node.right.value;
        }

        void clearRange(int l, int r) {
            root = clearRange(root, 1, n, l, r);
        }

        Node clearRange(Node node, int s, int e, int a, int b) {
            if (s > e || s > b || e < a) return node;
            if (s >= a && e <= b) {
                return new Node();
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            node.left = clearRange(node.left, s, m, a, b);
            node.right = clearRange(node.right, m + 1, e, a, b);
            node.value = node.left.value + node.right.value;
            return node;
        }

        int query(int l, int r) {
            return query(root, 1, n, l, r);
        }

        int query(Node node, int s, int e, int a, int b) {
            if (s > e || s > b || e < a) return 0;
            if (s >= a && e <= b) {
                return node.value;
            }
            int m = (s + e) / 2;
            if (node.left == null) node.left = new Node();
            if (node.right == null) node.right = new Node();
            pushDown(node, s, m, e);
            return query(node.left, s, m, a, b) + query(node.right, m + 1, e, a, b);
        }

        static class Node {
            Node left, right;
            int value, lazy;

            Node() {
            }

            Node(int v) {
                value = v;
            }

            @Override
            public String toString() {
                return "[" + value + ", " + lazy + "]";
            }
        }
    }
}


//package Strings;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;

public class String2 {

	static class SuffixAutomaton {

		int[] link, len;
		long[] ways;
		TreeMap<Character, Integer>[] next;
		int lst, idx;

		SuffixAutomaton(char[] s)
		{
			int n = s.length;
			link = new int[n<<1];
			len = new int[n<<1];
			ways = new long[n<<1];
			next = new TreeMap[n<<1];
			next[0] = new TreeMap<>();
			Arrays.fill(ways, -1);
			for(char c: s)
				addLetter(c);
		}
		long dfs(int idx) {
			if(ways[idx]!=-1)
				return ways[idx];
			long way =0;
			for (Map.Entry<Character, Integer> entry : next[idx].entrySet()) {
				Character c = entry.getKey();
				Integer x = entry.getValue();
				if(c=='$'&&idx!=0)
					way++;
				else {
					way+= dfs(x);
				}
			}
			return ways[idx]=way;
		}
		void traverse() {
			dfs(0);
		}
		void addLetter(char c)
		{
			int cur = ++idx, p = lst;
			//Keep adding to the suffix links of the last a link to the new cur
			while(!next[p].containsKey(c)) { next[p].put(c, cur); p = link[p]; }
			//this is the case where i am say adding a unique letter
			int q = next[p].get(c);
			//if i am not already done by checking that the last suffix link
			//is actually pointing at me
			if(q != cur)
				if(len[q] == len[p] + 1)
					link[cur] = q;
				else
				{
					int clone = ++idx;
					len[clone] = len[p] + 1;
					link[clone] = link[q];
					next[clone] = new TreeMap<>(next[q]);
					link[cur] = link[q] = clone;
					while(next[p].get(c) == q) { next[p].put(c, clone);	p = link[p]; }
				}
			len[cur] = len[lst] + 1;
			next[cur] = new TreeMap<>();
			lst = cur;
		}
	}

public static void main(String[] args) throws IOException{
	BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	String x = in.readLine()+"$";
	SuffixAutomaton sa = new SuffixAutomaton(x.toCharArray());
	sa.traverse();
	long ans = 0;

	for (int i = 0; i < sa.ways.length; i++) {
		long cur = sa.ways[i];
		ans+=(cur)*(cur+1)/2*(sa.len[i]-sa.len[sa.link[i]]);
	}
	System.out.println(ans);
}
}


import java.awt.Point;
import java.io.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.*;
import java.util.Map.Entry;

public class Tests {
	static Scanner in = new Scanner();
	static PrintWriter out = new PrintWriter(System.out);
	static SuffixAutomaton sa;

	public static void main(String[] test) throws NumberFormatException, IOException {
		String s = in.next();
		sa = new SuffixAutomaton(s.toCharArray());
		end = new int[s.length() * 2];
		int cur = sa.lst;
		end[cur] = 1;
		while (cur != 0) {
			cur = sa.link[cur];
			end[cur] = 1;
		}
		memo = new long[2 * s.length()];
		Arrays.fill(memo, -1);
		long ans = 0L;
		for (int i = 0; i <= sa.idx; i++) {
			long min_l = sa.len[sa.link[i]];
			long max_l = sa.len[i];
			long number_sub_in_state = max_l - min_l;
			long paths_to_end = dfs(i);
			long sum = paths_to_end * (paths_to_end + 1) * 1L / 2;
			ans += (sum * number_sub_in_state * 1L);
		}

		out.println(ans);
		out.flush();
		out.close();
	}

	static long memo[];
	static int end[];

	static long dfs(int state) {
		if (memo[state] != -1) {
			return memo[state];
		}
		long ret = 0L;
		if (end[state] == 1) {
			ret++;
		}
		for (Integer u : sa.next[state].values()) {
			ret += dfs(u);
		}
		memo[state] = ret;
		return ret;
	}

	static class SuffixAutomaton {
		int[] link, len;
		TreeMap<Character, Integer>[] next;
		int lst, idx;

		public SuffixAutomaton(char[] s) {
			int n = s.length;
			link = new int[n << 1];
			len = new int[n << 1];
			next = new TreeMap[n << 1];
			next[0] = new TreeMap<>();
			for (char c : s)
				addLetter(c);

		}

		private void addLetter(char c) {
			int cur = ++idx, p = lst;
			while (!next[p].containsKey(c)) {
				next[p].put(c, cur);
				p = link[p];
			}
			int q = next[p].get(c);
			if (q != cur) // If I stopped failing before reaching the root
				if (len[q] == len[p] + 1)
					link[cur] = q;
				else {
					int clone = ++idx;
					len[clone] = len[p] + 1;
					link[clone] = link[q];
					next[clone] = new TreeMap<>(next[q]);
					link[cur] = link[q] = clone;
					while (next[p].get(c) == q) {
						next[p].put(c, clone);
						p = link[p];
					}
				}
			len[cur] = len[lst] + 1;
			next[cur] = new TreeMap<>();
			lst = cur;
		}
	}

	static class Scanner {
		BufferedReader br;
		StringTokenizer st;

		Scanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		Scanner(String file) throws FileNotFoundException {
			br = new BufferedReader(new FileReader(file));
		}

		String next() throws IOException {
			while (st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();
		}

		int nextInt() throws NumberFormatException, IOException {
			return Integer.parseInt(next());
		}

		String nextLine() throws IOException {
			return br.readLine();
		}

		long nextLong() throws NumberFormatException, IOException {
			return Long.parseLong(next());
		}

		public int[] nextIntArray(int n) throws IOException {
			int[] a = new int[n];
			for (int i = 0; i < n; i++)
				a[i] = nextInt();
			return a;
		}

	}

}


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;

/**
 * Created by dhamada on 15/05/26.
 */
public class D {
    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        PrintWriter out = new PrintWriter(System.out);

        String s = in.nextToken();
        SuffixArray sa = new SuffixArray(s);
        sa.buildSA();
        sa.buildLCP();
        out.println(solve(sa.lcp));
        out.flush();
    }

    static long solve(int[] lcp) {
        int n = lcp.length;

        int[] left = new int[n];
        int[] right = new int[n];
        {
            Stack<Integer> st = new Stack<>();
            for (int i = 0; i < n; i++) {
                while (st.size() >= 1 && lcp[st.peek()] >= lcp[i]) {
                    st.pop();
                }
                left[i] = (st.size() == 0) ? -1 : st.peek();
                st.add(i);
            }
        }

        {
            Stack<Integer> st = new Stack<>();
            for (int i = n-1; i >= 0; i--) {
                while (st.size() >= 1 && lcp[st.peek()] >= lcp[i]) {
                    st.pop();
                }
                right[i] = (st.size() == 0) ? n : st.peek();
                st.add(i);
            }
        }

        BITRange rangeSum = new BITRange(n+10);
        for (int i = 1 ; i <= n ; i++) {
            rangeSum.addRange(i, i, lcp[i - 1]);
        }

        int[][] ranges = new int[n][];
        for (int i = 0; i < n ; i++) {
            ranges[i] = new int[]{ left[i], right[i], lcp[i], i };
        }

        Arrays.sort(ranges, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[2] - o2[2];
            }
        });

        long ret = 0;
        for (int[] r : ranges) {
            long height = rangeSum.get(r[3]+1);
            if (height  == 0) {
                continue;
            }
            long len = r[1] - r[0] - 1;

            ret += ((len * (len + 1)) / 2) * height;
            rangeSum.addRange(r[0]+2, r[1], -height);
        }
        return ret + 1L * n * (n + 1) / 2;
    }

    // 区間加算
    static class BITRange {
        BIT bit0;
        BIT bit1;
        BITRange(int n) {
            bit0 = new BIT(n);
            bit1 = new BIT(n);
        }

        void addRange(int l, int r, long x) {
            bit0.add(l, -x * (l-1));
            bit1.add(l, x);
            bit0.add(r+1, x * r);
            bit1.add(r+1, -x);
        }

        long range(int l, int r) {
            long right = bit0.sum(r) + bit1.sum(r) * r;
            long left = bit0.sum(l-1) + bit1.sum(l-1) * (l-1);
            return right - left;
        }

        long get(int i) {
            return range(i, i);
        }
    }

    // BIT, 1-indexed, range : [a,b]
    static class BIT {
        long N;
        long[] data;
        BIT(int n) {
            N = n;
            data = new long[n+1];
        }

        long sum(int i) {
            long s = 0;
            while (i > 0) {
                s += data[i];
                i -= i & (-i);
            }
            return s;
        }

        long range(int i, int j) {
            return sum(j) - sum(i-1);
        }

        void add(int i, long x) {
            while (i <= N) {
                data[i] += x;
                i += i & (-i);
            }
        }
    }

    static class SuffixArray {
        int n;
        char[] base;

        Integer[] sa;
        int[] rank;
        int[] tmp;
        int[] lcp;

        int compareNode(int i, int j, int k) {
            if (rank[i] != rank[j]) {
                return rank[i] - rank[j];
            } else {
                int ri = i + k <= n ? rank[i+k] : -1;
                int rj = j + k <= n ? rank[j+k] : -1;
                return ri - rj;
            }
        }

        SuffixArray(String x) {
            base = x.toCharArray();
            n = base.length;
        }

        void buildSA() {
            sa = new Integer[n+1];
            rank = new int[n+1];
            tmp = new int[n+1];
            for (int i = 0 ; i <= n ; i++) {
                sa[i] = i;
                rank[i] = (i < n) ? base[i] : -1;
            }
            for (int _k = 1 ; _k <= n ; _k *= 2) {
                final int k = _k;
                Arrays.sort(sa, new Comparator<Integer>() {
                    @Override
                    public int compare(Integer i, Integer j) {
                        return compareNode(i, j, k);
                    }
                });
                tmp[sa[0]] = 0;
                for (int i = 1 ; i <= n ; i++) {
                    tmp[sa[i]] = tmp[sa[i-1]] + ((compareNode(sa[i-1], sa[i], k) < 0) ? 1 : 0);
                }
                for (int i = 0 ; i <= n ; i++) {
                    rank[i] = tmp[i];
                }
            }
        }

        void buildLCP() {
            for (int i = 0 ; i <= n ; i++) {
                rank[sa[i]] = i;
            }
            lcp = new int[n];
            int h = 0;
            for (int i = 0 ; i < n ; i++) {
                int j = sa[rank[i]-1];
                if (h > 0) {
                    h--;
                }
                for (; j + h < n && i + h < n ; h++) {
                    if (base[j+h] != base[i+h]) {
                        break;
                    }
                }
                lcp[rank[i]-1] = h;
            }
        }
    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        private int next() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public char nextChar() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            if ('a' <= c && c <= 'z') {
                return (char)c;
            }
            if ('A' <= c && c <= 'Z') {
                return (char)c;
            }
            throw new InputMismatchException();
        }

        public String nextToken() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            StringBuilder res = new StringBuilder();
            do {
                res.append((char)c);
                c = next();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public int nextInt() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = next();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public long nextLong() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            long sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = next();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);
        }
    }

    static void debug(Object... o) {
        System.err.println(Arrays.deepToString(o));
    }
}


import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;

/**
 * Created by dhamada on 15/05/26.
 */
public class D {
    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        PrintWriter out = new PrintWriter(System.out);

        String s = in.nextToken();
        SuffixArray sa = new SuffixArray(s);
        sa.buildSA();
        sa.buildLCP();
        out.println(solve(sa.lcp));
        out.flush();
    }

    static long solve(int[] lcp) {
        int n = lcp.length;
        BITRange range = new BITRange(n+10);
        long ret = 0;
        for (int i = 1; i < n; i++) {
            if (lcp[i] < lcp[i-1]) {
                for (int k = lcp[i]+1 ; k <= lcp[i-1] ; k++) {
                    range.addRange(k, k, -range.get(k));
                }
            }
            if (lcp[i] >= 1) {
                range.addRange(1, lcp[i], 1);
                ret += range.range(1, n+1);
            }
        }
        return ret + 1L * n * (n + 1) / 2;
    }

    // 区間加算
    static class BITRange {
        BIT bit0;
        BIT bit1;
        BITRange(int n) {
            bit0 = new BIT(n);
            bit1 = new BIT(n);
        }

        void addRange(int l, int r, long x) {
            bit0.add(l, -x * (l-1));
            bit1.add(l, x);
            bit0.add(r+1, x * r);
            bit1.add(r+1, -x);
        }

        long range(int l, int r) {
            long right = bit0.sum(r) + bit1.sum(r) * r;
            long left = bit0.sum(l-1) + bit1.sum(l-1) * (l-1);
            return right - left;
        }

        long get(int i) {
            return range(i, i);
        }
    }

    // BIT, 1-indexed, range : [a,b]
    static class BIT {
        long N;
        long[] data;
        BIT(int n) {
            N = n;
            data = new long[n+1];
        }

        long sum(int i) {
            long s = 0;
            while (i > 0) {
                s += data[i];
                i -= i & (-i);
            }
            return s;
        }

        long range(int i, int j) {
            return sum(j) - sum(i-1);
        }

        void add(int i, long x) {
            while (i <= N) {
                data[i] += x;
                i += i & (-i);
            }
        }
    }

    static class SuffixArray {
        int n;
        char[] base;

        Integer[] sa;
        int[] rank;
        int[] tmp;
        int[] lcp;

        int compareNode(int i, int j, int k) {
            if (rank[i] != rank[j]) {
                return rank[i] - rank[j];
            } else {
                int ri = i + k <= n ? rank[i+k] : -1;
                int rj = j + k <= n ? rank[j+k] : -1;
                return ri - rj;
            }
        }

        SuffixArray(String x) {
            base = x.toCharArray();
            n = base.length;
        }

        void buildSA() {
            sa = new Integer[n+1];
            rank = new int[n+1];
            tmp = new int[n+1];
            for (int i = 0 ; i <= n ; i++) {
                sa[i] = i;
                rank[i] = (i < n) ? base[i] : -1;
            }
            for (int _k = 1 ; _k <= n ; _k *= 2) {
                final int k = _k;
                Arrays.sort(sa, new Comparator<Integer>() {
                    @Override
                    public int compare(Integer i, Integer j) {
                        return compareNode(i, j, k);
                    }
                });
                tmp[sa[0]] = 0;
                for (int i = 1 ; i <= n ; i++) {
                    tmp[sa[i]] = tmp[sa[i-1]] + ((compareNode(sa[i-1], sa[i], k) < 0) ? 1 : 0);
                }
                for (int i = 0 ; i <= n ; i++) {
                    rank[i] = tmp[i];
                }
            }
        }

        void buildLCP() {
            for (int i = 0 ; i <= n ; i++) {
                rank[sa[i]] = i;
            }
            lcp = new int[n];
            int h = 0;
            for (int i = 0 ; i < n ; i++) {
                int j = sa[rank[i]-1];
                if (h > 0) {
                    h--;
                }
                for (; j + h < n && i + h < n ; h++) {
                    if (base[j+h] != base[i+h]) {
                        break;
                    }
                }
                lcp[rank[i]-1] = h;
            }
        }
    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        private int next() {
            if (numChars == -1)
                throw new InputMismatchException();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public char nextChar() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            if ('a' <= c && c <= 'z') {
                return (char)c;
            }
            if ('A' <= c && c <= 'Z') {
                return (char)c;
            }
            throw new InputMismatchException();
        }

        public String nextToken() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            StringBuilder res = new StringBuilder();
            do {
                res.append((char)c);
                c = next();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        public int nextInt() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = next();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public long nextLong() {
            int c = next();
            while (isSpaceChar(c))
                c = next();
            long sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = next();
            }
            long res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = next();
            } while (!isSpaceChar(c));
            return res * sgn;
        }

        public boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);
        }
    }

    static void debug(Object... o) {
        System.err.println(Arrays.deepToString(o));
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.TreeMap;

public class SuffixAutomaton {

	static class State{

		int maxLen, suffixLink;
		boolean end;
		TreeMap<Character, Integer> next;

		public State(int maxLen){
			next = new TreeMap<>();
			this.maxLen = maxLen;
		}

		public State(int maxLen, int suffixLink){
			next = new TreeMap<>();
			this.maxLen = maxLen;
			this.suffixLink = suffixLink;
		}

	}

//	ArrayList<State> states;
//	ArrayList<Integer> endPos;
	State[] states;
	int[] endPos;
	int[] visited;
	int size, last;

	public SuffixAutomaton(String s){
//		states = new ArrayList<>();
//		endPos = new ArrayList<>();// carries the first end pos of the node
		states = new State[2*s.length() + 1];
		endPos = new int[2*s.length() + 1];
		states[0] = new State(0, -1);
//		endPos.add(0);
		size = last = 0;
		size++;
		build(s);
		markEndStates();
//		System.out.println(toString());
	}

	public void build(String s){
		for(int i = 0; i < s.length(); i++){
//			System.out.println("inserting character: " + s.charAt(i));
			insertCharacter(s.charAt(i), i);
//			System.out.println(toString());
		}
	}

	public void insertCharacter(char c, int i){
		// we need to set the node's
		//		maxLen
		//		suffixLink
		// 		transitions

		states[size] = new State(states[last].maxLen + 1);
//		states.add(newState);
		endPos[size] = i;
		int idx = size++;
		int p;
		for(p = last; p != -1 && !states[p].next.containsKey(c); p = states[p].suffixLink){
			states[p].next.put(c, idx);
		}
		if(p == -1){
			states[idx].suffixLink = 0;
		}else{
			// a split may be needed
			int q = states[p].next.get(c);
			if(states[p].maxLen + 1 == states[q].maxLen){
				// we don't need to split
				states[idx].suffixLink = q;
			}else{
				// we need to split
				int clone = size++;
				states[clone] = new State(states[p].maxLen + 1);
//				states.add(t);
				states[clone].next = new TreeMap<>(states[q].next);
				states[clone].suffixLink = states[q].suffixLink;
				endPos[clone]  = endPos[q];
				for(; p != -1 && states[p].next.get(c) == q; p = states[p].suffixLink){
					states[p].next.put(c, clone);
				}
				states[q].suffixLink = clone;
				states[idx].suffixLink = clone;
			}
		}
		last = idx;
	}

	public void markEndStates(){
		for(int i = last; i != -1; i = states[i].suffixLink){
			states[i].end = true;
		}
	}

	public int reachableEnds(int i){
//		System.out.println(i);
		if(visited[i] != -1)
			return visited[i];
		int c = 0;
		if(states[i].end)
			c++;
		for(Entry<Character, Integer> e: states[i].next.entrySet()){
//			if(states.get(e.getValue()).end){
//				c++;
//			}
			c += reachableEnds(e.getValue());
		}
		return c;
	}

	public String toString(){
		StringBuilder res = new StringBuilder();
		for(int i = 0; i < size; i++){
			res.append("node " + i + ":\n");
			State cur = states[i];
			res.append("\tsuffixLink: " + cur.suffixLink + "\n");
			res.append("\tend: " + cur.end + "\n");
			res.append("\tmaxLen: " + cur.maxLen + "\n");
			res.append("\tLinks: " + "\n");
			for(Entry<Character, Integer> e: cur.next.entrySet()){
				res.append(e.toString() + "\n");
			}
		}
		return res.toString();
	}

	public int countDistinct(){
		int f = 0;
		visited = new int[size];
		Arrays.fill(visited, -1);
		for(int i = 1; i < size; i++){
			visited[i] = reachableEnds(i);
//			System.out.println("reachable ends from node " + i + ": " + tmp);
			f += (states[i].maxLen - states[states[i].suffixLink].maxLen)*visited[i]*(visited[i] + 1) / 2;
//			f += tmp;
		}
		return f;
	}

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//		String s = br.readLine();
		SuffixAutomaton auto = new SuffixAutomaton(br.readLine());
		System.out.println(auto.countDistinct());
//		for(int i = 0; i < auto.size; i++){
//			System.out.println(i);
//			for(Entry<Character, Integer> e: auto.states.get(i).next.entrySet()){
//				System.out.println(e.toString());
//			}
//		}
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.TreeMap;

public class SuffixAutomaton {

	static class State{

		int maxLen, suffixLink;
		boolean end;
		TreeMap<Character, Integer> next;

		public State(int maxLen){
			next = new TreeMap<>();
			this.maxLen = maxLen;
		}

		public State(int maxLen, int suffixLink){
			next = new TreeMap<>();
			this.maxLen = maxLen;
			this.suffixLink = suffixLink;
		}

	}

//	ArrayList<State> states;
//	ArrayList<Integer> endPos;
	State[] states;
//	int[] endPos;
	int[] visited;
	int[] count;
	int size, last;

	public SuffixAutomaton(String s){
//		states = new ArrayList<>();
//		endPos = new ArrayList<>();// carries the first end pos of the node
		states = new State[2*s.length() + 1];
//		endPos = new int[2*s.length() + 1];
		states[0] = new State(0, -1);
		size = last = 0;
		size++;
		build(s);
		markEndStates();
	}

	public void build(String s){
		for(int i = 0; i < s.length(); i++){
			insertCharacter(s.charAt(i), i);
		}
	}

	public void insertCharacter(char c, int i){
		// we need to set the node's
		//		maxLen
		//		suffixLink
		// 		transitions

		states[size] = new State(states[last].maxLen + 1);
//		states.add(newState);
//		endPos[size] = i;
		int idx = size++;
		int p;
		for(p = last; p != -1 && !states[p].next.containsKey(c); p = states[p].suffixLink){
			states[p].next.put(c, idx);
		}
		if(p == -1){
			states[idx].suffixLink = 0;
		}else{
			// a split may be needed
			int q = states[p].next.get(c);
			if(states[p].maxLen + 1 == states[q].maxLen){
				// we don't need to split
				states[idx].suffixLink = q;
			}else{
				// we need to split
				int clone = size++;
				states[clone] = new State(states[p].maxLen + 1);
//				states.add(t);
				states[clone].next = new TreeMap<>(states[q].next);
				states[clone].suffixLink = states[q].suffixLink;
//				endPos[clone]  = endPos[q];
				for(; p != -1 && states[p].next.get(c) == q; p = states[p].suffixLink){
					states[p].next.put(c, clone);
				}
				states[q].suffixLink = clone;
				states[idx].suffixLink = clone;
			}
		}
		last = idx;
	}

	public void markEndStates(){
		for(int i = last; i != -1; i = states[i].suffixLink){
			states[i].end = true;
		}
	}

	public int reachableEnds(int i){
//		System.out.println(i);
		if(visited[i] != -1)
			return visited[i];
		int c = 0;
		if(states[i].end)
			c++;
		for(Entry<Character, Integer> e: states[i].next.entrySet()){
			c += reachableEnds(e.getValue());
		}
		return visited[i] = c;
	}

//	public int countDistinct(){
//		int f = 0;
//		visited = new int[size];
//		count = new int[size];
//		Arrays.fill(visited, -1);
//		Arrays.fill(count, -1);
//		for(int i = 1; i < size; i++){
//			if(visited[i] == -1)
//				visited[i] = reachableEnds(i);
//			f += (states[i].maxLen - states[states[i].suffixLink].maxLen)*visited[i]*(visited[i] + 1) / 2;
//		}
//		return f;
//	}

	public String toString(){
		StringBuilder res = new StringBuilder();
		for(int i = 0; i < size; i++){
			res.append("node " + i + ":\n");
			State cur = states[i];
			res.append("\tsuffixLink: " + cur.suffixLink + "\n");
			res.append("\tend: " + cur.end + "\n");
			res.append("\tmaxLen: " + cur.maxLen + "\n");
			res.append("\tLinks: " + "\n");
			for(Entry<Character, Integer> e: cur.next.entrySet()){
				res.append(e.toString() + "\n");
			}
		}
		return res.toString();
	}

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//		String s = br.readLine();
		SuffixAutomaton auto = new SuffixAutomaton(br.readLine());
//		System.out.println(auto.countDistinct());

		auto.visited = new int[auto.size];
		Arrays.fill(auto.visited, -1);
		auto.reachableEnds(0);
//		System.out.println(auto.reachableEnds(0));
//		System.out.println(Arrays.toString(auto.visited));
		int f = 0;
		for(int i = 1; i < auto.size; i++){
//			if(auto.visited[i] == -1)
//				auto.visited[i] = auto.reachableEnds(i);
			f += (auto.states[i].maxLen - auto.states[auto.states[i].suffixLink].maxLen)*auto.visited[i]*(auto.visited[i] + 1) / 2;
		}
		System.out.println(f);
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
//import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map.Entry;
import java.util.TreeMap;

public class SuffixAutomaton {

	static class State{

		int maxLen, suffixLink;
		boolean end;
		TreeMap<Character, Integer> next;

		public State(int maxLen){
			next = new TreeMap<>();
			this.maxLen = maxLen;
		}

		public State(int maxLen, int suffixLink){
			next = new TreeMap<>();
			this.maxLen = maxLen;
			this.suffixLink = suffixLink;
		}

	}

//	ArrayList<State> states;
//	ArrayList<Integer> endPos;
	State[] states;
	int[] endPos;
	long[] visited;
	int[] count;
	int size, last;

	public SuffixAutomaton(String s){
//		states = new ArrayList<>();
//		endPos = new ArrayList<>();// carries the first end pos of the node
		states = new State[2*s.length() + 1];
		endPos = new int[2*s.length() + 1];
		states[0] = new State(0, -1);
		size = last = 0;
		size++;
		build(s);
		markEndStates();
	}

	public void build(String s){
		for(int i = 0; i < s.length(); i++){
			insertCharacter(s.charAt(i), i);
		}
	}

	public void insertCharacter(char c, int i){
		// we need to set the node's
		//		maxLen
		//		suffixLink
		// 		transitions

		states[size] = new State(states[last].maxLen + 1);
//		states.add(newState);
		endPos[size] = i;
		int idx = size++;
		int p;
		for(p = last; p != -1 && !states[p].next.containsKey(c); p = states[p].suffixLink){
			states[p].next.put(c, idx);
		}
		if(p == -1){
			states[idx].suffixLink = 0;
		}else{
			// a split may be needed
			int q = states[p].next.get(c);
			if(states[p].maxLen + 1 == states[q].maxLen){
				// we don't need to split
				states[idx].suffixLink = q;
			}else{
				// we need to split
				int clone = size++;
				states[clone] = new State(states[p].maxLen + 1);
//				states.add(t);
				states[clone].next = new TreeMap<>(states[q].next);
				states[clone].suffixLink = states[q].suffixLink;
				endPos[clone]  = endPos[q];
				for(; p != -1 && states[p].next.get(c) == q; p = states[p].suffixLink){
					states[p].next.put(c, clone);
				}
				states[q].suffixLink = clone;
				states[idx].suffixLink = clone;
			}
		}
		last = idx;
	}

	public void markEndStates(){
		for(int i = last; i != -1; i = states[i].suffixLink){
			states[i].end = true;
		}
	}

	public long reachableEnds(int i){
//		System.out.println(i);
		if(visited[i] != -1)
			return visited[i];
		int c = 0;
		if(states[i].end)
			c++;
		for(Entry<Character, Integer> e: states[i].next.entrySet()){
			c += reachableEnds(e.getValue());
		}
		return visited[i] = c;
	}

//	public int countDistinct(){
//		int f = 0;
//		visited = new int[size];
//		count = new int[size];
//		Arrays.fill(visited, -1);
//		Arrays.fill(count, -1);
//		for(int i = 1; i < size; i++){
//			if(visited[i] == -1)
//				visited[i] = reachableEnds(i);
//			f += (states[i].maxLen - states[states[i].suffixLink].maxLen)*visited[i]*(visited[i] + 1) / 2;
//		}
//		return f;
//	}

	public String toString(){
		StringBuilder res = new StringBuilder();
		for(int i = 0; i < size; i++){
			res.append("node " + i + ":\n");
			State cur = states[i];
			res.append("\tsuffixLink: " + cur.suffixLink + "\n");
			res.append("\tend: " + cur.end + "\n");
			res.append("\tmaxLen: " + cur.maxLen + "\n");
			res.append("\tLinks: " + "\n");
			for(Entry<Character, Integer> e: cur.next.entrySet()){
				res.append(e.toString() + "\n");
			}
		}
		return res.toString();
	}

	public static void main(String[] args) throws IOException {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//		String s = br.readLine();
		SuffixAutomaton auto = new SuffixAutomaton(br.readLine());
//		System.out.println(auto.countDistinct());

		auto.visited = new long[auto.size];
		Arrays.fill(auto.visited, -1);
		auto.reachableEnds(0);
//		System.out.println(auto.reachableEnds(0));
//		System.out.println(Arrays.toString(auto.visited));
		long f = 0;
		for(int i = 1; i < auto.size; i++){
//			if(auto.visited[i] == -1)
//				auto.visited[i] = auto.reachableEnds(i);
			f += (auto.states[i].maxLen - auto.states[auto.states[i].suffixLink].maxLen)*auto.visited[i]*(auto.visited[i] + 1) / 2;
		}
		System.out.println(f);
	}

}