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++){
			if(visited[i] == -1)
				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.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;
	boolean[] 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);
		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;
		for(int i = 1; i < size; i++){
			int tmp = reachableEnds(i);
//			System.out.println("reachable ends from node " + i + ": " + tmp);
			f += (states[i].maxLen - states[states[i].suffixLink].maxLen)*tmp*(tmp + 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);
//		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()){
			c += reachableEnds(e.getValue());
		}
		return visited[i] = 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];
		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 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.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;
	boolean[] visited;
	int size, last;

	public SuffixAutomaton(String s){
		states = new ArrayList<>();
		endPos = new ArrayList<>();
		states.add(new State(0, -1));
		endPos.add(0);
		size = last = 0;
		size++;
		build(s);
		markEndStates();
	}

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

	public void insertCharacter(char c){
		// we need to set the node's
		//		maxLen
		//		suffixLink
		// 		transitions
		State newState = new State(states.get(last).maxLen + 1);
		states.add(newState);
		endPos.add(newState.maxLen - 1);
		int idx = size++;
		int p;
		for(p = last; p != -1 && !states.get(p).next.containsKey(c); p = states.get(p).suffixLink){
			states.get(p).next.put(c, idx);
		}
		if(p == -1){
			newState.suffixLink = 0;
		}else{
			// a split may be needed
			int q = states.get(p).next.get(c);
			if(states.get(p).maxLen + 1 == states.get(q).maxLen){
				// we don't need to split
				newState.suffixLink = q;
			}else{
				// we need to split
				int clone = size++;
				State t = new State(states.get(p).maxLen);
				states.add(t);
				t.next = states.get(q).next;
				t.suffixLink = states.get(q).suffixLink;
				endPos.add(endPos.get(q));
				for(; p != -1 && states.get(p).next.get(c) == q; p = states.get(p).suffixLink){
					states.get(p).next.put(c, clone);
				}
				states.get(q).suffixLink = clone;
				newState.suffixLink = clone;
			}
		}
		last = idx;
	}

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

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

	public int countDistinct(){
		int f = 0;
		for(int i = 1; i < size; i++){
			int tmp = reachableEnds(i);
//			System.out.println("reachable ends from node " + i + ": " + tmp);
			f += (states.get(i).maxLen - states.get(states.get(i).suffixLink).maxLen)*tmp*(tmp + 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.util.Arrays;
import java.util.Scanner;

public class SuffixAutomaton {
    long []co;
    long []ans;

    static class Node{
        int len,link=-1;
        int a[]=new int[26];
        boolean fin;
        public Node(int le){
            len=le;
        }
    }
    int max;
    Node nodes[];
    int last,sz;
    public SuffixAutomaton(int max){
        this.max=max;
        nodes =new Node[max];
        co=new long[max];
        ans=new long[max];

        nodes[0]=new Node(0);
        sz++;
    }
    public void add(char c){
        int ch=c-'a';
        int cur=sz++;
        nodes[cur]=new Node(nodes[last].len+1);
        int p;
        for(p=last;p!=-1 && nodes[p].a[ch]==0;p=nodes[p].link){
            nodes[p].a[ch]=cur;
        }
        if(p==-1)nodes[cur].link=0;
        else{
            int q=nodes[p].a[ch];
            if(nodes[p].len+1==nodes[q].len){
                nodes[cur].link=q;
            }
            else{
                int clone=sz++;
                nodes[clone]=new Node(nodes[p].len+1);
                nodes[clone].a=(int[])nodes[q].a.clone();
                nodes[clone].link=nodes[q].link;
                for(;p!=-1 && nodes[p].a[ch]==q;p=nodes[p].link){
                    nodes[p].a[ch]=clone;
                }
                nodes[q].link=nodes[cur].link=clone;
            }
        }
        last=cur;
    }

    public  long count(int n){
        if(co[n]!=0){
            return co[n];
        }
        for(int i=0;i<26;i++){
            if(nodes[n].a[i]!=0){
                co[n]+=count(nodes[n].a[i]);
            }
        }
        if(nodes[n].fin)co[n]++;
        return co[n];
    }
    int it=0;
    public long ans(int n){
        if(ans[n]!=-1)return ans[n];
        ans[n]=0;
        if(nodes[n].link==-1)ans[n]=0;
        else{
            long ac=nodes[n].len-nodes[nodes[n].link].len;
            long reb=co[n];
            ans[n]=ac*((reb*(reb+1))/2);
        }

        for(int i=0;i<26;i++){
            ans(nodes[n].a[i]);
        }
        return ans[n];
    }
    public void buildLink(){
        while(last!=0){
            nodes[last].fin=true;
            last=nodes[last].link;
        }
    }

    public static void main(String[] args) {
        SuffixAutomaton sa=new SuffixAutomaton(100000);
        Scanner sc=new Scanner (System.in);

        String s=sc.next();
        for (char ch:s.toCharArray()){
            sa.add(ch);
        }
        sa.buildLink();

        Arrays.fill(sa.ans, -1l);
        sa.count(0);
        sa.ans(0);
        long ans=0;
        for(int i=0;i<sa.ans.length;i++){
            if(sa.ans[i]==-1)sa.ans[i]=0;
        }
        for(int i=0;i<sa.ans.length;i++){
            ans+=sa.ans[i];
        }

        System.out.println(ans);

    }

}


import java.util.Arrays;
import java.util.Scanner;

public class SuffixAutomaton {
    long []co;
    long []ans;

    static class Node{
        int len,link=-1;
        int a[]=new int[26];
        boolean fin;
        public Node(int le){
            len=le;
        }
    }
    int max;
    Node nodes[];
    int last,sz;
    public SuffixAutomaton(int max){
        this.max=max;
        nodes =new Node[max];
        co=new long[max];
        ans=new long[max];

        nodes[0]=new Node(0);
        sz++;
    }
    public void add(char c){
        int ch=c-'a';
        int cur=sz++;
        nodes[cur]=new Node(nodes[last].len+1);
        int p;
        for(p=last;p!=-1 && nodes[p].a[ch]==0;p=nodes[p].link){
            nodes[p].a[ch]=cur;
        }
        if(p==-1)nodes[cur].link=0;
        else{
            int q=nodes[p].a[ch];
            if(nodes[p].len+1==nodes[q].len){
                nodes[cur].link=q;
            }
            else{
                int clone=sz++;
                nodes[clone]=new Node(nodes[p].len+1);
                nodes[clone].a=(int[])nodes[q].a.clone();
                nodes[clone].link=nodes[q].link;
                for(;p!=-1 && nodes[p].a[ch]==q;p=nodes[p].link){
                    nodes[p].a[ch]=clone;
                }
                nodes[q].link=nodes[cur].link=clone;
            }
        }
        last=cur;
    }

    public  long count(int n){
        if(co[n]!=0){
            return co[n];
        }
        for(int i=0;i<26;i++){
            if(nodes[n].a[i]!=0){
                co[n]+=count(nodes[n].a[i]);
            }
        }
        if(nodes[n].fin)co[n]++;
        return co[n];
    }
    int it=0;
    public long ans(int n){
        if(ans[n]!=-1)return ans[n];
        ans[n]=0;
        if(nodes[n].link==-1)ans[n]=0;
        else{
            long ac=nodes[n].len-nodes[nodes[n].link].len;
            long reb=co[n];
            ans[n]=ac*((reb*(reb+1))/2);
        }

        for(int i=0;i<26;i++){
            ans(nodes[n].a[i]);
        }
        return ans[n];
    }
    public void buildLink(){
        while(last!=0){
            nodes[last].fin=true;
            last=nodes[last].link;
        }
    }

    public static void main(String[] args) {
        SuffixAutomaton sa=new SuffixAutomaton(200005);
        Scanner sc=new Scanner (System.in);

        String s=sc.next();
        for (char ch:s.toCharArray()){
            sa.add(ch);
        }
        sa.buildLink();

        Arrays.fill(sa.ans, -1l);
        sa.count(0);
        sa.ans(0);
        long ans=0;
        for(int i=0;i<sa.ans.length;i++){
            if(sa.ans[i]==-1)sa.ans[i]=0;
        }
        for(int i=0;i<sa.ans.length;i++){
            ans+=sa.ans[i];
        }

        System.out.println(ans);

    }

}


import java.io.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.StringTokenizer;

/**
 * 123D
 * θ(|s|) time
 * θ(|s|) space
 *
 * @author artyom
 */
public class _123D implements Runnable {
    private BufferedReader in;
    private StringTokenizer tok;

    private long solve() throws IOException {
        SuffixTreeNode root = buildSuffixTree(nextToken() + '{');
        preprocess(root);
        return count(root);
    }

    private static long count(SuffixTreeNode node) {
        long cnt = ((node.isLeaf() ? node.end - 1 : node.end) - node.start) * (node.leaves + 1) * node.leaves / 2;
        if (!node.isLeaf()) {
            for (SuffixTreeNode child : node.activeChildren) {
                cnt += count(child);
            }
        }
        return cnt;
    }

    private static void preprocess(SuffixTreeNode node) {
        if (node.isLeaf()) {
            node.leaves = 1;
        } else {
            node.activeChildren = new LinkedList<>();
            for (SuffixTreeNode child : node.children) {
                if (child != null) {
                    preprocess(child);
                    node.leaves += child.leaves;
                    node.activeChildren.add(child);
                }
            }
        }
    }

    //--------------------------------------------------------------
    public static void main(String[] args) {
        new _123D().run();
    }

    @Override
    public void run() {
        try {
            in = new BufferedReader(new InputStreamReader(System.in));
            tok = null;
            System.out.print(solve());
            in.close();
        } catch (IOException e) {
            System.exit(0);
        }
    }

    private String nextToken() throws IOException {
        while (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    @SuppressWarnings("ConstantConditions")
    private static SuffixTreeNode buildSuffixTree(CharSequence s) {
        int n = s.length();
        byte[] a = new byte[n];
        for (int i = 0; i < n; i++) {
            a[i] = (byte) (s.charAt(i) - 'a');
        }
        SuffixTreeNode root = new SuffixTreeNode(0, 0, 0, null, null);
        SuffixTreeNode node = root;
        for (int i = 0, tail = 0; i < n; i++, tail++) {
            SuffixTreeNode last = null;
            while (tail >= 0) {
                SuffixTreeNode ch = node.children[a[i - tail]];
                while (ch != null && tail >= ch.length()) {
                    tail -= ch.length();
                    node = ch;
                    ch = ch.children[a[i - tail]];
                }
                if (ch == null) {
                    node.children[a[i]] = new SuffixTreeNode(i, n, node.depth(), i, node);
                    if (last != null) {
                        last.suffixLink = node;
                    }
                    last = null;
                } else {
                    byte t = a[(int) (ch.start + tail)];
                    if (t == a[i]) {
                        if (last != null) {
                            last.suffixLink = node;
                        }
                        break;
                    } else {
                        SuffixTreeNode splitNode = new SuffixTreeNode(ch.start, ch.start + tail, node.depth(), null, node);
                        splitNode.children[a[i]] = new SuffixTreeNode(i, n, ch.depth + tail, i, splitNode);
                        splitNode.children[t] = ch;
                        ch.start += tail;
                        ch.depth += tail;
                        ch.parent = splitNode;
                        node.children[a[i - tail]] = splitNode;
                        if (last != null) {
                            last.suffixLink = splitNode;
                        }
                        last = splitNode;
                    }
                }
                if (node == root) {
                    tail--;
                } else {
                    node = node.suffixLink;
                }
            }
        }
        return root;
    }

    private static final class SuffixTreeNode {
        long depth; // The number of characters from root to this node
        long start; // Inclusive
        long end; // Exclusive
        Long position;
        SuffixTreeNode parent;
        final SuffixTreeNode[] children;
        SuffixTreeNode suffixLink;
        // Additional properties
        Collection<SuffixTreeNode> activeChildren;
        long leaves;

        private SuffixTreeNode(long start, long end, long depth, Integer position, SuffixTreeNode parent) {
            this.start = start;
            this.end = end;
            this.parent = parent;
            this.depth = depth;
            if (position == null) {
                this.position = null;
                this.children = new SuffixTreeNode[27];
            } else {
                this.position = position - depth;
                // Save some space and time
                this.children = null;
            }
        }

        boolean isLeaf() {
            return position != null;
        }

        /**
         * @return the number of characters on the edge to the parent.
         */
        final long length() {
            return end - start;
        }

        /**
         * @return the number of characters on the path from the root to this node.
         */
        final long depth() {
            return depth + end - start;
        }

        @Override
        public String toString() {
            return "(" + start + ',' + (end - 1) + ')';
        }
    }
}


import java.io.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.StringTokenizer;

/**
 * 123D
 * θ(|s|) time
 * θ(|s|) space
 *
 * @author artyom
 */
public class _123D implements Runnable {
    private BufferedReader in;
    private StringTokenizer tok;

    private Object solve() throws IOException {
        SuffixTreeNode root = buildSuffixTree(nextToken() + '{');
        preprocess(root);
        return count(root);
    }

    private static long count(SuffixTreeNode node) {
        long cnt = 0;
        for (int i = node.start, end = node.isLeaf() ? node.end - 1 : node.end; i < end; i++) {
            cnt += (node.leaves + 1) * node.leaves / 2;
        }
        if (!node.isLeaf()) {
            for (SuffixTreeNode child : node.activeChildren) {
                cnt += count(child);
            }
        }
        return cnt;
    }

    private static void preprocess(SuffixTreeNode node) {
        if (node.isLeaf()) {
            node.leaves = 1;
        } else {
            node.activeChildren = new LinkedList<>();
            for (SuffixTreeNode child : node.children) {
                if (child != null) {
                    preprocess(child);
                    node.leaves += child.leaves;
                    node.activeChildren.add(child);
                }
            }
        }
    }

    //--------------------------------------------------------------
    public static void main(String[] args) {
        new _123D().run();
    }

    @Override
    public void run() {
        try {
            in = new BufferedReader(new InputStreamReader(System.in));
            tok = null;
            System.out.print(solve());
            in.close();
        } catch (IOException e) {
            System.exit(0);
        }
    }

    private String nextToken() throws IOException {
        while (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    @SuppressWarnings("ConstantConditions")
    private static SuffixTreeNode buildSuffixTree(CharSequence s) {
        int n = s.length();
        byte[] a = new byte[n];
        for (int i = 0; i < n; i++) {
            a[i] = (byte) (s.charAt(i) - 'a');
        }
        SuffixTreeNode root = new SuffixTreeNode(0, 0, 0, null, null);
        SuffixTreeNode node = root;
        for (int i = 0, tail = 0; i < n; i++, tail++) {
            SuffixTreeNode last = null;
            while (tail >= 0) {
                SuffixTreeNode ch = node.children[a[i - tail]];
                while (ch != null && tail >= ch.length()) {
                    tail -= ch.length();
                    node = ch;
                    ch = ch.children[a[i - tail]];
                }
                if (ch == null) {
                    node.children[a[i]] = new SuffixTreeNode(i, n, node.depth(), i, node);
                    if (last != null) {
                        last.suffixLink = node;
                    }
                    last = null;
                } else {
                    byte t = a[ch.start + tail];
                    if (t == a[i]) {
                        if (last != null) {
                            last.suffixLink = node;
                        }
                        break;
                    } else {
                        SuffixTreeNode splitNode = new SuffixTreeNode(ch.start, ch.start + tail, node.depth(), null, node);
                        splitNode.children[a[i]] = new SuffixTreeNode(i, n, ch.depth + tail, i, splitNode);
                        splitNode.children[t] = ch;
                        ch.start += tail;
                        ch.depth += tail;
                        ch.parent = splitNode;
                        node.children[a[i - tail]] = splitNode;
                        if (last != null) {
                            last.suffixLink = splitNode;
                        }
                        last = splitNode;
                    }
                }
                if (node == root) {
                    tail--;
                } else {
                    node = node.suffixLink;
                }
            }
        }
        return root;
    }

    private static final class SuffixTreeNode {
        int depth; // The number of characters from root to this node
        int start; // Inclusive
        int end; // Exclusive
        Integer position;
        SuffixTreeNode parent;
        final SuffixTreeNode[] children;
        SuffixTreeNode suffixLink;
        // Additional properties
        Collection<SuffixTreeNode> activeChildren;
        int leaves;

        private SuffixTreeNode(int start, int end, int depth, Integer position, SuffixTreeNode parent) {
            this.start = start;
            this.end = end;
            this.parent = parent;
            this.depth = depth;
            if (position == null) {
                this.position = null;
                this.children = new SuffixTreeNode[27];
            } else {
                this.position = position - depth;
                // Save some space and time
                this.children = null;
            }
        }

        boolean isLeaf() {
            return position != null;
        }

        /**
         * @return the number of characters on the edge to the parent.
         */
        final int length() {
            return end - start;
        }

        /**
         * @return the number of characters on the path from the root to this node.
         */
        final int depth() {
            return depth + end - start;
        }

        @Override
        public String toString() {
            return "(" + start + ',' + (end - 1) + ')';
        }
    }
}


import java.io.*;
import java.util.Collection;
import java.util.LinkedList;
import java.util.StringTokenizer;

/**
 * 123D
 * θ(|s|) time
 * θ(|s|) space
 *
 * @author artyom
 */
public class _123D implements Runnable {
    private BufferedReader in;
    private StringTokenizer tok;

    private long solve() throws IOException {
        SuffixTreeNode root = buildSuffixTree(nextToken() + '{');
        preprocess(root);
        return count(root);
    }

    private static long count(SuffixTreeNode node) {
        long cnt = ((node.isLeaf() ? node.end - 1 : node.end) - node.start) * (node.leaves + 1) * node.leaves / 2;
        if (!node.isLeaf()) {
            for (SuffixTreeNode child : node.activeChildren) {
                cnt += count(child);
            }
        }
        return cnt;
    }

    private static void preprocess(SuffixTreeNode node) {
        if (node.isLeaf()) {
            node.leaves = 1;
        } else {
            node.activeChildren = new LinkedList<>();
            for (SuffixTreeNode child : node.children) {
                if (child != null) {
                    preprocess(child);
                    node.leaves += child.leaves;
                    node.activeChildren.add(child);
                }
            }
        }
    }

    //--------------------------------------------------------------
    public static void main(String[] args) {
        new _123D().run();
    }

    @Override
    public void run() {
        try {
            in = new BufferedReader(new InputStreamReader(System.in));
            tok = null;
            System.out.print(solve());
            in.close();
        } catch (IOException e) {
            System.exit(0);
        }
    }

    private String nextToken() throws IOException {
        while (tok == null || !tok.hasMoreTokens()) {
            tok = new StringTokenizer(in.readLine());
        }
        return tok.nextToken();
    }

    @SuppressWarnings("ConstantConditions")
    private static SuffixTreeNode buildSuffixTree(CharSequence s) {
        int n = s.length();
        byte[] a = new byte[n];
        for (int i = 0; i < n; i++) {
            a[i] = (byte) (s.charAt(i) - 'a');
        }
        SuffixTreeNode root = new SuffixTreeNode(0, 0, 0, null, null);
        SuffixTreeNode node = root;
        for (int i = 0, tail = 0; i < n; i++, tail++) {
            SuffixTreeNode last = null;
            while (tail >= 0) {
                SuffixTreeNode ch = node.children[a[i - tail]];
                while (ch != null && tail >= ch.length()) {
                    tail -= ch.length();
                    node = ch;
                    ch = ch.children[a[i - tail]];
                }
                if (ch == null) {
                    node.children[a[i]] = new SuffixTreeNode(i, n, node.depth(), i, node);
                    if (last != null) {
                        last.suffixLink = node;
                    }
                    last = null;
                } else {
                    byte t = a[ch.start + tail];
                    if (t == a[i]) {
                        if (last != null) {
                            last.suffixLink = node;
                        }
                        break;
                    } else {
                        SuffixTreeNode splitNode = new SuffixTreeNode(ch.start, ch.start + tail, node.depth(), null, node);
                        splitNode.children[a[i]] = new SuffixTreeNode(i, n, ch.depth + tail, i, splitNode);
                        splitNode.children[t] = ch;
                        ch.start += tail;
                        ch.depth += tail;
                        ch.parent = splitNode;
                        node.children[a[i - tail]] = splitNode;
                        if (last != null) {
                            last.suffixLink = splitNode;
                        }
                        last = splitNode;
                    }
                }
                if (node == root) {
                    tail--;
                } else {
                    node = node.suffixLink;
                }
            }
        }
        return root;
    }

    private static final class SuffixTreeNode {
        int depth; // The number of characters from root to this node
        int start; // Inclusive
        int end; // Exclusive
        Integer position;
        SuffixTreeNode parent;
        final SuffixTreeNode[] children;
        SuffixTreeNode suffixLink;
        // Additional properties
        Collection<SuffixTreeNode> activeChildren;
        int leaves;

        private SuffixTreeNode(int start, int end, int depth, Integer position, SuffixTreeNode parent) {
            this.start = start;
            this.end = end;
            this.parent = parent;
            this.depth = depth;
            if (position == null) {
                this.position = null;
                this.children = new SuffixTreeNode[27];
            } else {
                this.position = position - depth;
                // Save some space and time
                this.children = null;
            }
        }

        boolean isLeaf() {
            return position != null;
        }

        /**
         * @return the number of characters on the edge to the parent.
         */
        final int length() {
            return end - start;
        }

        /**
         * @return the number of characters on the path from the root to this node.
         */
        final int depth() {
            return depth + end - start;
        }

        @Override
        public String toString() {
            return "(" + start + ',' + (end - 1) + ')';
        }
    }
}


import java.io.*;
import java.util.Arrays;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class CF123_D_String {

    private static class SuffixAutomaton {
        int maxSize;
        int[] link;
        int[] len;
        int nodeCount;
        int last;
        int root;
        TreeMap<Character, Integer>[] to;
        boolean[] finalState;

        long[] dp;

        public SuffixAutomaton(String s) {
            int n = s.length();
            maxSize = n << 1 + 1;
            nodeCount = 1;
            last = root = 0;
            link = new int[maxSize];
            len = new int[maxSize];
            to = new TreeMap[maxSize];
            to[root] = new TreeMap<>();
            for (int i = 0; i < n; i++)
                addLetter(s.charAt(i));
            finalState = new boolean[maxSize];
            markFinalStates(last);
            dp = new long[maxSize];
            Arrays.fill(dp, -1);
        }

        void addLetter(char c) {
            int node = nodeCount++;
            len[node] = len[last] + 1;
            to[node] = new TreeMap<>();
            while (to[last].get(c) == null) {
                to[last].put(c, node);
                last = link[last];
            }
            int t = to[last].get(c);
            if (t == node)
                link[node] = 0;
            else if (len[t] == len[last] + 1)
                link[node] = t;
            else {
                int q = nodeCount++;
                len[q] = len[last] + 1;
                to[q] = new TreeMap<>(to[t]);
                link[q] = link[t];
                link[t] = link[node] = q;
                while (to[last].get(c) != null && to[last].get(c) == t) {
                    to[last].put(c, q);
                    last = link[last];
                }
            }
            last = node;
        }

        private void markFinalStates(int node) {
            while (node != root) {
                finalState[node] = true;
                node = link[node];
            }
            finalState[root] = true;
        }

        public long solve() {
            solve(root);
            long ans = 0;
            for (int node = 1; node < maxSize; node++) {
                long x = dp[node];
                if (x != -1)
                    ans += ((x * (x + 1)) >> 1) * (len[node] - len[link[node]]);
            }
            return ans;
        }

        private long solve(int node) {
            if (dp[node] != -1)
                return dp[node];
            long ans = finalState[node] ? 1 : 0;
            for (Map.Entry<Character, Integer> e : to[node].entrySet())
                ans += solve(e.getValue());
            return dp[node] = ans;
        }
    }

    public static void main(String[] args) throws IOException {
        MyScanner sc = new MyScanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        SuffixAutomaton sa = new SuffixAutomaton(sc.next());
        out.println(sa.solve());
        out.flush();
        out.close();
    }

    private static class MyScanner {
        StringTokenizer st;
        BufferedReader br;

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

        public MyScanner(String filename) throws IOException {
            br = new BufferedReader(new FileReader(new File(filename)));
        }

        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 {
            String x = next();
            StringBuilder sb = new StringBuilder("0");
            double res = 0, f = 1;
            boolean dec = false, neg = false;
            int start = 0;
            if (x.charAt(0) == '-') {
                neg = true;
                start++;
            }
            for (int i = start; i < x.length(); i++)
                if (x.charAt(i) == '.') {
                    res = Long.parseLong(sb.toString());
                    sb = new StringBuilder("0");
                    dec = true;
                } else {
                    sb.append(x.charAt(i));
                    if (dec)
                        f *= 10;
                }
            res += Long.parseLong(sb.toString()) / f;
            return res * (neg ? -1 : 1);
        }

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


import java.io.*;
import java.util.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

import static java.lang.Math.*;
import static java.util.Arrays.*;
import java.util.*;
// aoj2292
public class Main {
    public static void main(String[]args){
        new Main().run();
    }

    private void run() {
        Scanner sc = new Scanner(System.in);
        String s = sc.next();
        long res = solve(s+'$');
        System.out.println(res);
    }

    private long solve(String s) {
        int n = s.length();
        int[] sa = suffixArray_log(s);
        int[] sainv = new int[sa.length];
        for (int i = 0; i < sa.length; i++) {
            sainv[sa[i]] = i;
        }
        int[] lcp = calcLCP(sa, s);
        E[] ordLcp = new E[lcp.length];
        for (int i = 0; i < lcp.length; i++) {
            ordLcp[i] = new E(i, lcp[i]);
        }
//      debug("lcp",lcp);
        sort(ordLcp);
        RMQ rmq = new RMQ(lcp.length);
        for (int i = 0; i < lcp.length; i++) {
            rmq.update(i, lcp[i]);
        }

        X = 0;
        long res = 0;
        UnionFind uf = new UnionFind(s.length());
        for(int k = n-1,il=0;k>=1;k--){
            X++;
            uf.num[sainv[n-1-k]]++;
            while(il<ordLcp.length && ordLcp[il].k == k){
                uf.union(ordLcp[il].i, ordLcp[il].i+1);
                il++;
            }
            res += X;
//          debug(k,X);
        }
        return res;
    }

    private void debug(Object... os) {
        System.err.println(deepToString(os));
    }

    private long func(long n) {
        return (n+1)*n/2;
    }

    long X;

    class UnionFind{
        final int[] tree;
        long[] num;

        public UnionFind(int n){
            this.tree=new int[n];
            num=new long[n];
            fill(tree,-1);
        }
        void union(int x,int y){
            x=root(x);
            y=root(y);
            if(x!=y){
                if(tree[x]>tree[y]){
                    int t=x;x=y;y=t;
                }
                // x <- y
                X -= func(num[x]);
                X -= func(num[y]);
                num[x] += num[y];
                X += func(num[x]);

                tree[x]+=tree[y];
                tree[y]=x;
            }
        }

        boolean find(int x,int y){
            return root(x)==root(y);
        }

        int root(int x){
            return tree[x]<0?x:(tree[x]=root(tree[x]));
        }

        int size(int x){
            return -tree[root(x)];
        }
    }

    class RMQ {
        private int[] dat;
        private int n;
        public RMQ(int _n){
            n=1;
            while(n<_n)n<<=1;
            dat=new int[n+n];
            Arrays.fill(dat,Integer.MAX_VALUE);
        }

        public void update(int i,int a) {
            i+=n-1;
            dat[i] = a;
            while(i>0) {
                i=(i-1)>>1;
                dat[i] = Math.min(dat[(i<<1)+1],dat[(i<<1)+2]);
            }
        }

        public int query(int l,int r) {
            return query(l,r,0,0,n);
        }

        private int query(int a,int b,int i,int l,int r){
            if(r<=a || b<=l)return Integer.MAX_VALUE;
            if(a<=l && r<=b)return dat[i];
            int vl = query(a,b,(i<<1)+1,l,(l+r)>>>1);
            int vr = query(a,b,(i<<1)+2,(l+r)>>>1,r);
            return Math.min(vl,vr);
        }
    }

    class E implements Comparable<E>{
        int i,k;

        public E(int i, int k) {
            super();
            this.i = i;
            this.k = k;
        }
        public int compareTo(E o) {
            return - (k - o.k);
        }
        @Override
        public String toString() {
            return "E [i=" + i + ", k=" + k + "]";
        }

    }

    public int[] calcLCP(int[] SA,String s) {
        if(SA.length != s.length())throw new IllegalArgumentException();
        int n = s.length();
        int[] rank=new int[n];// s[i..] がSAにおいて何番目か.
        for(int i=0;i<n;i++)rank[SA[i]]=i;
        int[] lcp=new int[n-1];
        for(int i=0,h=0;i<n;i++)if(rank[i]<n-1) {
            while(s.charAt(i+h) == s.charAt(SA[rank[i]+1]+h))h++;
            lcp[rank[i]]=h;
            if(h>0)h--;
        }
        return lcp;
    }

    /**
     * s に対するsuffix arrayを返す.
     * s[n-1] は,それ以外のどの文字よりも小さくなければならない.
     * O(n log n).
     * n=800000 で1s くらい.
     * wataさんのライブラリを参考にした.
     */
    public int[] suffixArray_log(String s){
        int n=s.length()-1;
        char[] cs = s.toCharArray();
        int[] is=new int[n+1];
        for (int i = 0; i < n+1; i++) {
            is[i] = cs[i];
        }
        int[] si = indexSort(is);
        int[] a=new int[n+1],b=new int[n+1];
        for(int h=0;;){
            for (int i = 0; i < n; i++) {
                int x=si[i+1],y=si[i];
                b[i+1]=b[i];
                if(is[x]>is[y] || is[x+h]>is[y+h])b[i+1]++;
            }
            for (int i = 0; i < n+1; i++) {
                is[si[i]] = b[i];
            }
            if(b[n]==n)break;
            h = max(1,h<<1);
            for(int k=h;k>=0;k-=h){
                fill(b,0);
                b[0]=k;
                for (int i = k; i < n+1; i++) {
                    b[is[i]]++;
                }
                for (int i = 0; i < n; i++) {
                    b[i+1]+=b[i];
                }
                for(int i=n;i>=0;i--){
                    a[--b[si[i]+k>n?0:is[si[i]+k]]]=si[i];
                }
                int[] tmp=si;si=a;a=tmp;
            }
        }
        return si;
    }

    private int[] indexSort(int[] is) {
        int n=is.length;
        long[] ls=new long[n];
        for (int i = 0; i < n; i++) {
            ls[i]=(long)is[i]<<32 | i;
        }
        sort(ls);
        int[]res=new int[n];
        for (int i = 0; i < n; i++) {
            res[i]=(int)ls[i];
        }
        return res;
    }

    private String rev(String s) {
        return new StringBuilder(s).reverse().toString();
    }

    private String sand(String s) {
        StringBuilder b = new StringBuilder();
        for(char c:s.toCharArray()){
            b.append('*');
            b.append(c);
        }
        b.append('*');
        return b.toString();
    }
}


import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.util.Comparator;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.io.IOException;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.NoSuchElementException;
import java.math.BigInteger;
import java.io.InputStream;

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

class TaskD {
    public void solve(int testNumber, InputReader in, OutputWriter out) {
        String s = in.readString();
        final SuffixAutomaton automaton = new SuffixAutomaton(s);
        int size = automaton.size;
        int[] qty = new int[size];
        int current = 0;
        for (int i = 0; i < s.length(); i++) {
            current = automaton.to[automaton.findEdge(current, s.charAt(i))];
            qty[current]++;
        }
        int[] order = ArrayUtils.createOrder(size);
        ArrayUtils.sort(order, new IntComparator() {
            public int compare(int first, int second) {
                return automaton.length[second] - automaton.length[first];
            }
        });
        for (int i : order) {
            if (automaton.link[i] != -1)
                qty[automaton.link[i]] += qty[i];
        }
        int[] paths = new int[size];
        Arrays.fill(paths, -1);
        paths[0] = 1;
        int[] reverseFirst = new int[size];
        int[] reverseNext = new int[4 * s.length()];
        int[] reverseTo = new int[4 * s.length()];
        Arrays.fill(reverseFirst, -1);
        int edgeCount = 0;
        for (int i = 0; i < size; i++) {
            int edge = automaton.first[i];
            while (edge != -1) {
                int to = automaton.to[edge];
                reverseNext[edgeCount] = reverseFirst[to];
                reverseFirst[to] = edgeCount;
                reverseTo[edgeCount++] = i;
                edge = automaton.next[edge];
            }
        }
        for (int i = 1; i < size; i++)
            countPaths(i, paths, reverseFirst, reverseNext, reverseTo);
        long answer = 0;
        for (int i = 1; i < size; i++)
            answer += (long) qty[i] * (qty[i] + 1) / 2 * paths[i];
        out.printLine(answer);
    }

    private int countPaths(int vertex, int[] paths, int[] reverseFirst, int[] reverseNext, int[] reverseTo) {
        if (paths[vertex] != -1)
            return paths[vertex];
        paths[vertex] = 0;
        int edge = reverseFirst[vertex];
        while (edge != -1) {
            paths[vertex] += countPaths(reverseTo[edge], paths, reverseFirst, reverseNext, reverseTo);
            edge = reverseNext[edge];
        }
        return paths[vertex];
    }
}

class InputReader {

	private InputStream stream;
	private byte[] buf = new byte[1024];
	private int curChar;
	private int numChars;
	private SpaceCharFilter filter;

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

	public int read() {
		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 String readString() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		StringBuilder res = new StringBuilder();
		do {
			res.appendCodePoint(c);
			c = read();
		} while (!isSpaceChar(c));
		return res.toString();
	}

	public boolean isSpaceChar(int c) {
		if (filter != null)
			return filter.isSpaceChar(c);
		return isWhitespace(c);
	}

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

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

class OutputWriter {
	private final PrintWriter writer;

	public OutputWriter(OutputStream outputStream) {
		writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
	}

	public OutputWriter(Writer writer) {
		this.writer = new PrintWriter(writer);
	}

	public void print(Object...objects) {
		for (int i = 0; i < objects.length; i++) {
			if (i != 0)
				writer.print(' ');
			writer.print(objects[i]);
		}
	}

    public void printLine(Object...objects) {
		print(objects);
		writer.println();
	}

	public void close() {
		writer.close();
	}

	}

class SuffixAutomaton {
    public final int[] length;
    public final int[] link;
    public final int[] first;
    public final int[] next;
    public final int[] to;
    public final int[] label;
    public int size;
    public int last;

    public SuffixAutomaton(final CharSequence s) {
        this(new IntList() {
            @Override
            public int get(int index) {
                return s.charAt(index);
            }

            public void set(int index, int value) {
                throw new UnsupportedOperationException();
            }

            @Override
            public int size() {
                return s.length();
            }

            public void add(int value) {
                throw new UnsupportedOperationException();
            }
        });
    }

    public SuffixAutomaton(IntList s) {
        int count = s.size();
        length = new int[2 * count];
        link = new int[2 * count];
        first = new int[2 * count];
        next = new int[4 * count];
        label = new int[4 * count];
        to = new int[4 * count];
        Arrays.fill(first, -1);
        link[0] = -1;
        size = 1;
        int edgeSize = 0;
        last = 0;
        for (int i = 0; i < s.size(); i++) {
            int c = s.get(i);
            int current = size++;
            length[current] = length[last] + 1;
            for (int previous = last; ; previous = link[previous]) {
                if (previous == -1) {
                    link[current] = 0;
                    break;
                }
                int index = findEdge(previous, c);
                if (index != -1) {
                    int curLink = to[index];
                    if (length[previous] + 1 == length[curLink])
                        link[current] = curLink;
                    else {
                        int clone = size++;
                        length[clone] = length[previous] + 1;
                        link[clone] = link[curLink];
                        int linkEdge = first[curLink];
                        while (linkEdge != -1) {
                            next[edgeSize] = first[clone];
                            first[clone] = edgeSize;
                            label[edgeSize] = label[linkEdge];
                            to[edgeSize++] = to[linkEdge];
                            linkEdge = next[linkEdge];
                        }
                        for (; previous != -1; previous = link[previous]) {
                            int edge = findEdge(previous, c);
                            if (edge == -1 || to[edge] != curLink)
                                break;
                            to[edge] = clone;
                        }
                        link[current] = link[curLink] = clone;
                    }
                    break;
                }
                next[edgeSize] = first[previous];
                first[previous] = edgeSize;
                label[edgeSize] = c;
                to[edgeSize++] = current;
            }
            last = current;
        }
    }

    public int findEdge(int vertex, int label) {
        int edge = first[vertex];
        while (edge != -1) {
            if (this.label[edge] == label)
                return edge;
            edge = next[edge];
        }
        return -1;
    }
}

class ArrayUtils {
	private static int[] tempInt = new int[0];

	public static int[] createOrder(int size) {
		int[] order = new int[size];
		for (int i = 0; i < size; i++)
			order[i] = i;
		return order;
	}

	public static int[] sort(int[] array, IntComparator comparator) {
		return sort(array, 0, array.length, comparator);
	}

	public static int[] sort(int[] array, int from, int to, IntComparator comparator) {
		ensureCapacityInt(to - from);
		System.arraycopy(array, from, tempInt, 0, to - from);
		sortImpl(array, from, to, tempInt, 0, to - from, comparator);
		return array;
	}

	private static void ensureCapacityInt(int size) {
		if (tempInt.length >= size)
			return;
		size = Math.max(size, tempInt.length << 1);
		tempInt = new int[size];
	}

	private static void sortImpl(int[] array, int from, int to, int[] temp, int fromTemp, int toTemp, IntComparator comparator) {
		if (to - from <= 1)
			return;
		int middle = (to - from) >> 1;
		int tempMiddle = fromTemp + middle;
		sortImpl(temp, fromTemp, tempMiddle, array, from, from + middle, comparator);
		sortImpl(temp, tempMiddle, toTemp, array, from + middle, to, comparator);
		int index = from;
		int index1 = fromTemp;
		int index2 = tempMiddle;
		while (index1 < tempMiddle && index2 < toTemp) {
			if (comparator.compare(temp[index1], temp[index2]) <= 0)
				array[index++] = temp[index1++];
			else
				array[index++] = temp[index2++];
		}
		if (index1 != tempMiddle)
			System.arraycopy(temp, index1, array, index, tempMiddle - index1);
		if (index2 != toTemp)
			System.arraycopy(temp, index2, array, index, toTemp - index2);
	}

	}

interface IntComparator {
    public static final IntComparator DEFAULT = new IntComparator() {
        public int compare(int first, int second) {
            if (first < second)
                return -1;
            if (first > second)
                return 1;
            return 0;
        }
    };

	public int compare(int first, int second);
}

abstract class IntCollection {
	public abstract IntIterator iterator();
	public abstract int size();

	}

interface IntIterator {
	public int value() throws NoSuchElementException;
	/*
	 * @throws NoSuchElementException only if iterator already invalid
	 */
	public void advance() throws NoSuchElementException;
	public boolean isValid();
}

abstract class IntList extends IntCollection {
	private static final int INSERTION_THRESHOLD = 8;

	public abstract int get(int index);
	public abstract void set(int index, int value);

	public IntIterator iterator() {
		return new IntIterator() {
			private int size = size();
			private int index = 0;

			public int value() throws NoSuchElementException {
				if (!isValid())
					throw new NoSuchElementException();
				return get(index);
			}

			public void advance() throws NoSuchElementException {
				if (!isValid())
					throw new NoSuchElementException();
				index++;
			}

			public boolean isValid() {
				return index < size;
			}
		};
	}

	private void swap(int first, int second) {
		if (first == second)
			return;
		int temp = get(first);
		set(first, get(second));
		set(second, temp);
	}

	public IntSortedList inPlaceSort(IntComparator comparator) {
		quickSort(0, size() - 1, size(), comparator);
		return new IntSortedArray(this, comparator);
	}

	private void quickSort(int from, int to, int remaining, IntComparator comparator) {
		if (to - from < INSERTION_THRESHOLD) {
			insertionSort(from, to, comparator);
			return;
		}
		if (remaining == 0) {
			heapSort(from, to, comparator);
			return;
		}
		remaining >>= 1;
		int pivotIndex = (from + to) >> 1;
		int pivot = get(pivotIndex);
		swap(pivotIndex, to);
		int storeIndex = from;
		int equalIndex = to;
		for (int i = from; i < equalIndex; i++) {
			int value = comparator.compare(get(i), pivot);
			if (value < 0)
				swap(storeIndex++, i);
			else if (value == 0)
				swap(--equalIndex, i--);
		}
		quickSort(from, storeIndex - 1, remaining, comparator);
		for (int i = equalIndex; i <= to; i++)
			swap(storeIndex++, i);
		quickSort(storeIndex, to, remaining, comparator);
	}

	private void heapSort(int from, int to, IntComparator comparator) {
		for (int i = (to + from - 1) >> 1; i >= from; i--)
			siftDown(i, to, comparator);
		for (int i = to; i > from; i--) {
			swap(from, i);
			siftDown(from, i - 1, comparator);
		}
	}

	private void siftDown(int start, int end, IntComparator comparator) {
		int value = get(start);
		while (true) {
			int child = (start << 1) + 1;
			if (child > end)
				return;
			int childValue = get(child);
			if (child + 1 <= end) {
				int otherValue = get(child + 1);
				if (comparator.compare(otherValue, childValue) > 0) {
					child++;
					childValue = otherValue;
				}
			}
			if (comparator.compare(value, childValue) >= 0)
				return;
			swap(start, child);
			start = child;
		}
	}

	private void insertionSort(int from, int to, IntComparator comparator) {
		for (int i = from + 1; i <= to; i++) {
			int value = get(i);
			for (int j = i - 1; j >= from; j--) {
				if (comparator.compare(get(j), value) <= 0)
					break;
				swap(j, j + 1);
			}
		}
	}

	public IntSortedList sort(IntComparator comparator) {
		return new IntArray(this).inPlaceSort(comparator);
	}

	}

abstract class IntSortedList extends IntList {
	protected final IntComparator comparator;

	protected IntSortedList(IntComparator comparator) {
		this.comparator = comparator;
	}

	public void set(int index, int value) {
		throw new UnsupportedOperationException();
	}

	public IntSortedList inPlaceSort(IntComparator comparator) {
		if (comparator == this.comparator)
			return this;
		throw new UnsupportedOperationException();
	}

	public IntSortedList sort(IntComparator comparator) {
		if (comparator == this.comparator)
			return this;
		return super.sort(comparator);
	}

	protected void ensureSorted() {
		int size = size();
		if (size == 0)
			return;
		int last = get(0);
		for (int i = 1; i < size; i++) {
			int current = get(i);
			if (comparator.compare(last, current) > 0)
				throw new IllegalArgumentException();
			last = current;
		}
	}

	}

class IntSortedArray extends IntSortedList {
	private final int[] array;

	public IntSortedArray(int[] array) {
		this(array, IntComparator.DEFAULT);
	}

	public IntSortedArray(IntCollection collection) {
		this(collection, IntComparator.DEFAULT);
	}

	public IntSortedArray(int[] array, IntComparator comparator) {
		super(comparator);
		this.array = array;
		ensureSorted();
	}

	public IntSortedArray(IntCollection collection, IntComparator comparator) {
		super(comparator);
		array = new int[collection.size()];
		int i = 0;
		for (IntIterator iterator = collection.iterator(); iterator.isValid(); iterator.advance())
			array[i++] = iterator.value();
		ensureSorted();
	}

	public int get(int index) {
		return array[index];
	}

	public int size() {
		return array.length;
	}
}

class IntArray extends IntList {
	private final int[] array;

	public IntArray(int[] array) {
		this.array = array;
	}

	public IntArray(IntCollection collection) {
		array = new int[collection.size()];
		int i = 0;
		for (IntIterator iterator = collection.iterator(); iterator.isValid(); iterator.advance())
			array[i++] = iterator.value();
	}

	public int get(int index) {
		return array[index];
	}

	public void set(int index, int value) {
		array[index] = value;
	}

	public int size() {
		return array.length;
	}

	}


//package round92;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;

public class D {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	public Integer[] doLarssonSadakane(final char[] str)
	{
		int n = str.length;
		final int[] g = new int[n+1];
		int[] b = new int[n+1];
		Integer[] v = new Integer[n+1];
		for(int i = 0;i < n+1;i++){
			v[i] = i;
			g[i] = i == n ? -1 : str[i];
		}
		b[0] = 0; b[n] = 0;

		Arrays.sort(v, new Comparator<Integer>(){
			public int compare(Integer a, Integer b){
				if(a == b)return -1;
				return g[a] - g[b];
			}
		});
		for(int h = 1;b[n] != n;h *= 2){
			final int u = h;
			Comparator<Integer> comp = new Comparator<Integer>(){
				public int compare(Integer a, Integer b){
					if(a == b)return -1;
					if(g[a] - g[b] != 0)return g[a] - g[b];
//					int x = a+u<g.length ? g[a+u] : 0;
//					int y = b+u<g.length ? g[b+u] : 0;
//					return x - y;
					return g[a+u] - g[b+u];
				}
			};
			Arrays.sort(v, comp);
			for(int i = 0;i < n;i++){
				b[i+1] = b[i] + (comp.compare(v[i], v[i+1]) < 0 ? 1 : 0);
			}
			for(int i = 0;i < n+1;i++)g[v[i]] = b[i];
		}
		return v;
	}

	void solve()
	{
		char[] str = ns(100000);
		Integer[] ls = doLarssonSadakane(str);
		int[] lcp = buildLCP(str, ls);
		int n = str.length;
		int[][] start = new int[n+2][3];
		long local = 0;
		long ret = 0;
		int p = 0;
		for(int i = 1;i <= n;i++){
//			if(lcp[i] > 0){
				local += lcp[i];
				if(lcp[i-1] > lcp[i]){
					while(p > 0){
						if(lcp[i] < start[p-1][0]){
							local -= (long)(i-1-start[p-1][2]+1) * (start[p-1][1] - start[p-1][0]+1);
							p--;
						}else if(lcp[i] <= start[p-1][1]){
							local -= (long)(i-1-start[p-1][2]+1) * (start[p-1][1] - (lcp[i]+1)+1);
							start[p-1][1] = lcp[i];
							break;
						}else{
							break;
						}
					}
				}else if(lcp[i-1] < lcp[i]){
					start[p][0] = lcp[i-1]+1;
					start[p][1] = lcp[i];
					start[p][2] = i;
					p++;
				}
				ret += local;
//			}
		}
		out.println(ret+(long)n*(n+1)/2);
	}

	int[] buildLCP(char[] str, Integer[] ls)
	{
		int n = str.length;
		int h = 0;
		int[] lcp = new int[n+1];
		int[] b = new int[n+1];
		for(int i = 0;i < n+1;i++)b[ls[i]] = i;
		for(int i = 0;i < n+1;i++){
			if(b[i] != 0){
				for(int j = ls[b[i]-1]; j+h<n && i+h<n && str[j+h] == str[i+h]; h++);
				lcp[b[i]] = h;
			}else{
				lcp[b[i]] = -1;
			}
			if(h > 0)h--;
		}
		return lcp;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static int sumFenwick(int[] ft, int i)
	{
		int sum = 0;
		for(i++;i > 0;i -= i&-i)sum += ft[i];
		return sum;
	}

	public static void addFenwick(int[] ft, int i, int v)
	{
		int n = ft.length;
		for(i++;i < n;i += i&-i)ft[i] += v;
	}

	public static int findGFenwick(int[] ft, int v)
	{
		int i = 0;
		int n = ft.length;
		for(int b = Integer.highestOneBit(n);b != 0 && i < n;b >>= 1){
			if(i + b < n){
				int t = i + b;
				if(v >= ft[t]){
					i = t;
					v -= ft[t];
				}
			}
		}
		return v != 0 ? -(i+1) : i-1;
	}

	public static int sumRangeFenwick(int[] ft, int[] ftp, int i)
	{
		int n = ft.length;
		int sum = 0;
		for(i++;i > 0;i -= i&-i){
			sum += ft[i];
			int num = i&-i;
			for(int j=i+(i&-i);j < n;j += j&-j){
				sum += ftp[j]*num;
			}
		}
		return sum;
	}

	public static void addRangeFenwick(int[] ft, int[] ftp, int i, int v)
	{
		int n = ft.length;
		for(i++;i > 0;i -= i&-i){
			ftp[i] += v;
			int w = v*(i&-i);
			for(int j = i;j < n;j += j&-j){
				ft[j] += w;
			}
		}
	}

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

	public int ni()
	{
		try {
			int num = 0;
			boolean minus = false;
			while((num = is.read()) != -1 && !((num >= '0' && num <= '9') || num == '-'));
			if(num == '-'){
				num = 0;
				minus = true;
			}else{
				num -= '0';
			}

			while(true){
				int b = is.read();
				if(b >= '0' && b <= '9'){
					num = num * 10 + (b - '0');
				}else{
					return minus ? -num : num;
				}
			}
		} catch (IOException e) {
		}
		return -1;
	}

	public long nl()
	{
		try {
			long num = 0;
			boolean minus = false;
			while((num = is.read()) != -1 && !((num >= '0' && num <= '9') || num == '-'));
			if(num == '-'){
				num = 0;
				minus = true;
			}else{
				num -= '0';
			}

			while(true){
				int b = is.read();
				if(b >= '0' && b <= '9'){
					num = num * 10 + (b - '0');
				}else{
					return minus ? -num : num;
				}
			}
		} catch (IOException e) {
		}
		return -1;
	}

	public String ns()
	{
		try{
			int b = 0;
			StringBuilder sb = new StringBuilder();
			while((b = is.read()) != -1 && (b == '\r' || b == '\n' || b == ' '));
			if(b == -1)return "";
			sb.append((char)b);
			while(true){
				b = is.read();
				if(b == -1)return sb.toString();
				if(b == '\r' || b == '\n' || b == ' ')return sb.toString();
				sb.append((char)b);
			}
		} catch (IOException e) {
		}
		return "";
	}

	public char[] ns(int n)
	{
		char[] buf = new char[n];
		try{
			int b = 0, p = 0;
			while((b = is.read()) != -1 && (b == ' ' || b == '\r' || b == '\n'));
			if(b == -1)return null;
			buf[p++] = (char)b;
			while(p < n){
				b = is.read();
				if(b == -1 || b == ' ' || b == '\r' || b == '\n')break;
				buf[p++] = (char)b;
			}
			return Arrays.copyOf(buf, p);
		} catch (IOException e) {
		}
		return null;
	}

	double nd() { return Double.parseDouble(ns()); }
	boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


//package round92re;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Comparator;
import java.util.InputMismatchException;

public class D {
	InputStream is;
	PrintWriter out;
	String INPUT = "a";

	void solve()
	{
		char[] s = ns(100005);
		Integer[] sa = doLarssonSadakane(s);
		int[] lcp = buildLCP(s, sa);
		int n = s.length;
		int[][] t = new int[n+2][]; // [from, num]
		int p = 0;
		int h = 0;
		long ret = 0;
		for(int i = 0;i < n;i++){
			int plus = n-sa[i+1]-h;
			if(plus > 0){
				t[p++] = new int[]{i, plus};
				h += plus;
			}
			if(i < n-1){
				while(p > 0 && h > lcp[i+2]){
					int minus = Math.min(h-lcp[i+2], t[p-1][1]);
//					tr(ret, t[p-1], minus);
					ret += (long)(i-t[p-1][0]+1)*(i-t[p-1][0]+2)/2*minus;
					t[p-1][1] -= minus;
					h -= minus;
					if(t[p-1][1] == 0){
						p--;
					}
				}
			}else{
				while(p > 0){
					int minus = t[p-1][1];
					ret += (long)(n-t[p-1][0])*(n-t[p-1][0]+1)/2*minus;
					p--;
				}
			}
		}
		out.println(ret);
	}

	public static Integer[] doLarssonSadakane(char[] str)
	{
		int n = str.length;
		final int[] g = new int[n+1];
		int[] b = new int[n+1];
		Integer[] v = new Integer[n+1];
		for(int i = 0;i < n+1;i++){
			v[i] = i;
			g[i] = i == n ? -1 : str[i];
		}
		b[0] = 0; b[n] = 0;

		Arrays.sort(v, new Comparator<Integer>(){
			public int compare(Integer a, Integer b){
				if(a == b)return -1;
				return g[a] - g[b];
			}
		});
		for(int h = 1;b[n] != n;h *= 2){
			final int u = h;
			Comparator<Integer> comp = new Comparator<Integer>(){
				public int compare(Integer a, Integer b){
					if(a == b)return -1;
					if(g[a] - g[b] != 0)return g[a] - g[b];
					return g[a+u] - g[b+u];
				}
			};
			Arrays.sort(v, comp);
			for(int i = 0;i < n;i++){
				b[i+1] = b[i] + (comp.compare(v[i], v[i+1]) < 0 ? 1 : 0);
			}
			for(int i = 0;i < n+1;i++)g[v[i]] = b[i];
		}
		return v;
	}

	public static int[] buildLCP(char[] str, Integer[] ls)
	{
		int n = str.length;
		int h = 0;
		int[] lcp = new int[n+1];
		int[] b = new int[n+1];
		for(int i = 0;i < n+1;i++)b[ls[i]] = i;
		for(int i = 0;i < n+1;i++){
			if(b[i] != 0){
				for(int j = ls[b[i]-1]; j+h<n && i+h<n && str[j+h] == str[i+h]; h++);
				lcp[b[i]] = h;
			}else{
				lcp[b[i]] = -1;
			}
			if(h > 0)h--;
		}
		return lcp;
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new PrintWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

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

	private byte[] inbuf = new byte[1024];
	private int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private char[][] nm(int n, int m)
	{
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.util.LinkedList;
import java.util.Arrays;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import java.io.BufferedReader;
import java.math.BigInteger;
import java.io.PrintStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Comparator;
import java.io.IOException;
import java.util.StringTokenizer;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author shu_mj @ http://shu-mj.com
 */
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);
		TaskJ solver = new TaskJ();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskJ {
    Scanner in;
    PrintWriter out;

    public void solve(int testNumber, Scanner in, PrintWriter out) {
        this.in = in;
        this.out = out;
        run();
    }

    void run() {
        String s = in.next();
        SuffixArray sa = new SuffixArray(s.toCharArray());
        sa.buildHs();
        int n = s.length();
        UnionFindSet uf = new UnionFindSet(n + 1);
        List<P>[] ps = new List[n];
        for (int i = 0; i < n; i++) {
            ps[i] = new LinkedList<P>();
        }
        for (int i = 0; i < n; i++) {
            ps[sa.hs[i]].add(new P(sa.si[i], sa.si[i + 1]));
        }
        int[] cnt = new int[n + 1];
        Arrays.fill(cnt, 1);
        cnt[n] = 0;
        long res = 0;
        long crt = 1;
        for (int i = n - 1; i >= 0; i--) {
            for (P p : ps[i]) {
                int l = uf.find(p.x);
                int r = uf.find(p.y);
                crt -= (long) cnt[l] * (cnt[l] + 1) / 2;
                crt -= (long) cnt[r] * (cnt[r] + 1) / 2;
                uf.pre[l] = r;
                cnt[r] += cnt[l];
                crt += (long) cnt[r] * (cnt[r] + 1) / 2;
            }
            res += crt;
        }
        out.println(res);
    }
    class P {
        int x;
        int y;

        P(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
}

class Scanner {
    BufferedReader br;
    StringTokenizer st;

    public Scanner(InputStream in) {
        br = new BufferedReader(new InputStreamReader(in));
        eat("");
    }

    private void eat(String s) {
        st = new StringTokenizer(s);
    }

    public String nextLine() {
        try {
            return br.readLine();
        } catch (IOException e) {
            return null;
        }
    }

    public boolean hasNext() {
        while (!st.hasMoreTokens()) {
            String s = nextLine();
            if (s == null)
                return false;
            eat(s);
        }
        return true;
    }

    public String next() {
        hasNext();
        return st.nextToken();
    }

}

class SuffixArray {
    public int n;
    public char[] cs;
    public int[] si, is;// ソート後と元のインデックスの対応

    public int[] indexSort(int[] is) {
        int[] c = new int[128];
        for (int i : is) c[i]++;
        for (int i = 1; i < 128; i++) c[i] += c[i - 1];
        int n = is.length;
        int[] si = new int[n];
        for (int i = n - 1; i >= 0; i--) si[--c[is[i]]] = i;
        return si;
    }

    public SuffixArray(char[] t) {
        n = t.length;
        cs = new char[n + 1];
        System.arraycopy(t, 0, cs, 0, n);
        cs[n] = 0;// 番兵(他の全ての値より小さくすること)
        is = new int[n + 1];
        for (int i = 0; i <= n; i++) is[i] = cs[i];
        si = indexSort(is);
        int[] a = new int[n + 1], b = new int[n + 1];
        for (int h = 0; ; ) {
            for (int i = 0; i < n; i++) {
                int x = si[i + 1], y = si[i];
                b[i + 1] = b[i];
                if (is[x] > is[y] || is[x + h] > is[y + h]) b[i + 1]++;
            }
            for (int i = 0; i <= n; i++) is[si[i]] = b[i];
            if (b[n] == n) break;
            h = Math.max(1, h << 1);
            for (int k = h; k >= 0; k -= h) {
                Arrays.fill(b, 0);
                b[0] = k;
                for (int i = k; i <= n; i++) b[is[i]]++;
                for (int i = 0; i < n; i++) b[i + 1] += b[i];
                for (int i = n; i >= 0; i--) {
                    a[--b[si[i] + k > n ? 0 : is[si[i] + k]]] = si[i];
                }
                int[] tmp = si; si = a; a = tmp;
            }
        }
    }

    public int[] hs;// hs[i]:=ソート後のsuffix のi とi+1 のLCP

    public void buildHs() {
        hs = new int[n + 1];
        for (int i = 0, h = 0; i < n; i++) {
            for (int j = si[is[i] - 1]; cs[i + h] == cs[j + h]; h++) ;
            hs[is[i] - 1] = h;
            if (h > 0) h--;
        }
    }

}

class UnionFindSet {
    public int[] pre;

    public UnionFindSet(int n) {
        pre = new int[n];
        for (int i = 0; i < n; i++) pre[i] = i;
    }

    public int find(int x) {
        if (pre[x] != x) pre[x] = find(pre[x]);
        return pre[x];
    }

}


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

public class AString implements Runnable {
    static final int INF = 1000000;

    static class IntervalTree {
        int[] subtreeMin;
        int n;

        public IntervalTree(int n) {
            this.n = n;
            subtreeMin = new int[4 * n + 10];
            Arrays.fill(subtreeMin, INF);
        }

        void update(int at, int by) {
            internalUpdate(0, 0, n - 1, at, by);
        }

        private void internalUpdate(int root, int rl, int rr, int at, int by) {
            if (rl == rr)
                subtreeMin[root] = by;
            else {
                int rm = (rl + rr) / 2;
                if (at <= rm)
                    internalUpdate(root * 2 + 1, rl, rm, at, by);
                else
                    internalUpdate(root * 2 + 2, rm + 1, rr, at, by);
                subtreeMin[root] = Math.min(subtreeMin[root * 2 + 1], subtreeMin[root * 2 + 2]);
            }
        }

        int get(int l, int r) {
            return internalGet(0, 0, n - 1, l, r);
        }

        private int internalGet(int root, int rl, int rr, int l, int r) {
            l = Math.max(l, rl);
            r = Math.min(r, rr);
            if (l > r) return INF;
            if (l == rl && r == rr)
                return subtreeMin[root];
            int rm = (rl + rr) / 2;
            return Math.min(internalGet(root * 2 + 1, rl, rm, l, r), internalGet(root * 2 + 2, rm + 1, rr, l, r));
        }
    }

    private void solve() throws IOException {
        String s = nextToken() + (char) ('a' - 1);
        int[] id = new int[s.length()];
        int[] cnt = new int[Math.max(27, s.length())];
        int[] perm = new int[s.length()];
        IntervalTree eqLen = new IntervalTree(s.length() - 1);
        for (int i = 0; i < s.length(); ++i) {
            id[i] = s.charAt(i) - 'a' + 1;
            ++cnt[id[i]];
        }
        int[] ptr = new int[cnt.length];
        ptr[0] = 0;
        for (int i = 0; i + 1 < cnt.length; ++i)
            ptr[i + 1] = ptr[i] + cnt[i];
        for (int i = 0; i < s.length(); ++i) {
            perm[ptr[id[i]]++] = i;
        }
        for (int i = 0; i + 1 < s.length(); ++i)
            if (id[perm[i]] != id[perm[i + 1]])
                eqLen.update(i, 0);
        int len = 1;
        int[] nperm = new int[s.length()];
        int[] nid = new int[s.length()];
        while (len < s.length()) {
            Arrays.fill(cnt, 0);
            for (int x : id) ++cnt[x];
            ptr[0] = 0;
            for (int i = 0; i + 1 < cnt.length; ++i)
                ptr[i + 1] = ptr[i] + cnt[i];
            for (int second = 0; second < s.length(); ++second) {
                int first = (perm[second] - len + s.length()) % s.length();
                nperm[ptr[id[first]]++] = first;
            }
            int lastId = 0;
            for (int i = 0; i < s.length(); ++i) {
                if (i != 0) {
                    int p1 = nperm[i];
                    int p2 = nperm[i - 1];
                    if (id[p1] != id[p2]) {
                        ++lastId;
                    } else {
                        int n1 = (p1 + len) % s.length();
                        int n2 = (p2 + len) % s.length();
                        if (id[n1] != id[n2]) {
                            int pos1 = ptr[id[n1]] - 1;
                            int pos2 = ptr[id[n2]] - 1;
                            eqLen.update(i - 1, len + eqLen.get(Math.min(pos1, pos2), Math.max(pos1, pos2) - 1));
                            ++lastId;
                        }
                    }
                }
                nid[nperm[i]] = lastId;
            }
            {
                int[] tmp = perm;
                perm = nperm;
                nperm = tmp;
                tmp = id;
                id = nid;
                nid = tmp;
            }
            len *= 2;
        }
        int[] stackCnt = new int[s.length()];
        int[] stackLen = new int[s.length()];
        int stackPos = 0;
        int stackTotalLen = 0;
        long res = 0;
        for (int i = 1; i < s.length(); ++i) {
            int cur = perm[i];
            int commonLen = eqLen.get(i - 1, i - 1);
            //System.out.println(cur + " " + commonLen);
            int curLen = s.length() - cur - 1;
            while (stackTotalLen > commonLen) {
                int by = Math.min(stackLen[stackPos - 1], stackTotalLen - commonLen);
                int byCnt = stackCnt[stackPos - 1] + i;
                res += (long) byCnt * (byCnt + 1) / 2 * by;
                stackLen[stackPos - 1] -= by;
                if (stackLen[stackPos - 1] == 0) --stackPos;
                stackTotalLen -= by;
            }
            if (stackTotalLen != commonLen) throw new RuntimeException();
            if (curLen > commonLen) {
                stackCnt[stackPos] = -i;
                stackLen[stackPos] = curLen - commonLen;
                ++stackPos;
                stackTotalLen += curLen - commonLen;
            }
        }
        while (stackTotalLen > 0) {
            int by = stackLen[stackPos - 1];
            int byCnt = stackCnt[stackPos - 1] + s.length();
            res += (long) byCnt * (byCnt + 1) / 2 * by;
            stackLen[stackPos - 1] -= by;
            if (stackLen[stackPos - 1] == 0) --stackPos;
            stackTotalLen -= by;
        }
        writer.println(res);
    }

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

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

    public void run() {
        try {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
            writer = new PrintWriter(System.out);
            solve();
            reader.close();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

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

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

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

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


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define M 100005

int rank[M],sa[M],X[M],Y[M],high[M],init[M];
int buc[M];

inline bool equ(int *r,int a,int b,int l) {return (r[a]==r[b]&&r[a+l]==r[b+l]);}
inline void rsort(int *x, int *y, int n, int m){
    for(int i=0; i<m; i++) buc[i] = 0;
    for(int i=0; i<n; i++) buc[ x[y[i]] ] ++;
    for(int i=1; i<m; i++) buc[i] += buc[i-1];
    for(int i=n-1; i>=0; i--) sa[ --buc[ x[y[i]] ] ] = y[i];
}

void suffix(int n, int m = 128) {
    int *x = X, *y = Y;
    for(int i=0;i<n;i++) x[i] = init[y[i]=i];
    rsort(x, y, n, m);
    int l = 1;
    do{
        int v = 0, p = 1;
        for(int i=n-l; i<n; i++) y[v++] = i;
        for(int i=0; i<n; i++) if(sa[i] >= l) y[v++] = sa[i] - l;
        rsort(x, y, n, m);
        swap(x, y); x[sa[0]] = 0;
        for(int i=1; i<n; i++) x[ sa[i] ] = equ(y,sa[i-1],sa[i],l) ? p-1 : p++;
        l <<= 1; m = p;
    } while( m < n );

    for(int i=1; i<n; i++) rank[sa[i]] = i;
    int k = 0;
    for(int i=0; i<n-1; i++) {
        if(k) k--;
        for(int j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++);
        high[rank[i]]=k;
    }
}

char s[M];
int n;

int stk[M], sfi[M], top;
int main() {
    while(~scanf("%s", s)){
        int n = strlen(s);
    //  s[n] = '~';
    //  s[++n] = 0;
        for(int i=0;i<=n;i++) init[i] = s[i];
        suffix(n+1);

//      for(int i=1;i<=n;i++){
//          printf("%d %d\t%s\n", high[i], sa[i], s+sa[i]);
//      }

        LL ans=0, one=0;
        stk[top=0] = 1;
        sfi[0] = 1;
        sfi[1] = n;
        high[n+1] = 0;
        for(int i=1;i<=n;i++){
            one+=n-sa[i]-max(high[i+1], high[i]);
            //printf("=== %d\n", one);
            if(i==1) continue;
            //printf("+++ %d\n", n-sa[i]-max(high[i+1], high[i]));
            while(top>=0&&high[stk[top]]>=high[i]){
                //printf("~~ %d:%d %d:%d\n", i, high[i], stk[top], high[stk[top]]);
                LL len = high[stk[top]] - max(high[stk[top-1]], high[i]);
                LL a = i-sfi[top]+1;
                LL cnt = len*(a*(a+1)/2);
                //printf("?? %I64d %I64d\n", a, len);
                ans+=cnt;
                top--;
            }

            stk[++top] = i;
            sfi[top] = min(sfi[top], i);
            sfi[top+1] = n;
    //      printf("stk:: ");
    //      for(int j=0;j<=top;j++){
    //          printf("%d ", high[stk[j]]);
    //      }puts("");
        }
        for(int i=1;i<=top;i++){
            LL len = high[stk[i]] - high[stk[i-1]];
            LL a = n-sfi[i]+2;
            LL cnt = len*(a*(a+1)/2);
            //printf("?? %I64d %I64d\n", a, len);
            ans+=cnt;
        }
        printf("%I64d\n", ans+one);
    }
}


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define M 100005

int rank[M],sa[M],X[M],Y[M],high[M],init[M];
int buc[M];

inline bool equ(int *r,int a,int b,int l) {return (r[a]==r[b]&&r[a+l]==r[b+l]);}
inline void rsort(int *x, int *y, int n, int m){
	for(int i=0; i<m; i++) buc[i] = 0;
	for(int i=0; i<n; i++) buc[ x[y[i]] ] ++;
	for(int i=1; i<m; i++) buc[i] += buc[i-1];
	for(int i=n-1; i>=0; i--) sa[ --buc[ x[y[i]] ] ] = y[i];
}

void suffix(int n, int m = 128) {
	int *x = X, *y = Y;
	for(int i=0;i<n;i++) x[i] = init[y[i]=i];
	rsort(x, y, n, m);
	int l = 1;
	do{
		int v = 0, p = 1;
		for(int i=n-l; i<n; i++) y[v++] = i;
		for(int i=0; i<n; i++) if(sa[i] >= l) y[v++] = sa[i] - l;
		rsort(x, y, n, m);
		swap(x, y); x[sa[0]] = 0;
		for(int i=1; i<n; i++) x[ sa[i] ] = equ(y,sa[i-1],sa[i],l) ? p-1 : p++;
		l <<= 1; m = p;
	} while( m < n );

	for(int i=1; i<n; i++) rank[sa[i]] = i;
	int k = 0;
	for(int i=0; i<n-1; i++) {
		if(k) k--;
		for(int j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++);
		high[rank[i]]=k;
	}
}

char s[M];
int n;

int stk[M], top;
int main() {
	scanf("%s", s);
	int n = strlen(s);
//	s[n] = '~';
//	s[++n] = 0;
	for(int i=0;i<=n;i++) init[i] = s[i];
	suffix(n+1);

//	for(int i=1;i<=n;i++){
//		printf("%d %d\t%s\n", high[i], sa[i], s+sa[i]);
//	}

	LL ans=0, one=0;
	stk[top=0] = high[1];
	high[n+1] = 0;
	for(int i=1;i<=n;i++){
		one+=n-sa[i]-max(high[i+1], high[i]);
		if(i==1) continue;
		//printf("+++ %d\n", n-sa[i]-max(high[i+1], high[i]));
		while(top>=0&&high[stk[top]]>high[i]){
			//printf("~~ %d:%d %d:%d\n", i, high[i], stk[top], high[stk[top]]);
			LL len = high[stk[top]] - max(high[stk[top-1]], high[i]);
			LL a = i-stk[top]+1;
			LL cnt = len*(a*(a+1)/2);
			//printf("?? %I64d %I64d\n", a, len);
			ans+=cnt;
			top--;
		}
		if(high[i]!=high[stk[top]]) stk[++top] = i;
//		printf("stk:: ");
//		for(int j=0;j<=top;j++){
//			printf("%d ", high[stk[j]]);
//		}puts("");
	}
	for(int i=1;i<=top;i++){
		LL len = high[stk[i]] - high[stk[i-1]];
		LL a = n-stk[i]+2;
		LL cnt = len*(a*(a+1)/2);
		//printf("?? %I64d %I64d\n", a, len);
		ans+=cnt;
	}
	printf("%I64d\n", ans+one);
}


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define M 100005

int rank[M],sa[M],X[M],Y[M],high[M],init[M];
int buc[M];

inline bool equ(int *r,int a,int b,int l) {return (r[a]==r[b]&&r[a+l]==r[b+l]);}
inline void rsort(int *x, int *y, int n, int m){
	for(int i=0; i<m; i++) buc[i] = 0;
	for(int i=0; i<n; i++) buc[ x[y[i]] ] ++;
	for(int i=1; i<m; i++) buc[i] += buc[i-1];
	for(int i=n-1; i>=0; i--) sa[ --buc[ x[y[i]] ] ] = y[i];
}

void suffix(int n, int m = 128) {
	int *x = X, *y = Y;
	for(int i=0;i<n;i++) x[i] = init[y[i]=i];
	rsort(x, y, n, m);
	int l = 1;
	do{
		int v = 0, p = 1;
		for(int i=n-l; i<n; i++) y[v++] = i;
		for(int i=0; i<n; i++) if(sa[i] >= l) y[v++] = sa[i] - l;
		rsort(x, y, n, m);
		swap(x, y); x[sa[0]] = 0;
		for(int i=1; i<n; i++) x[ sa[i] ] = equ(y,sa[i-1],sa[i],l) ? p-1 : p++;
		l <<= 1; m = p;
	} while( m < n );

	for(int i=1; i<n; i++) rank[sa[i]] = i;
	int k = 0;
	for(int i=0; i<n-1; i++) {
		if(k) k--;
		for(int j = sa[rank[i]-1] ; init[i+k] == init[j+k] ; k++);
		high[rank[i]]=k;
	}
}

char s[M];
int n;

int stk[M], top;
int main() {
	scanf("%s", s);
	int n = strlen(s);
//	s[n] = '~';
//	s[++n] = 0;
	for(int i=0;i<=n;i++) init[i] = s[i];
	suffix(n+1);

//	for(int i=1;i<=n;i++){
//		printf("%d %d\t%s\n", high[i], sa[i], s+sa[i]);
//	}

	LL ans=0, one=0;
	stk[top=0] = high[1];
	high[n+1] = 0;
	for(int i=2;i<=n;i++){
		int mlen = high[i];
		one+=n-sa[i]-max(high[i+1], high[i]);
		//printf("+++ %d\n", n-sa[i]-max(high[i+1], high[i]));
		while(top>=0&&high[stk[top]]>high[i]){
			//printf("~~ %d:%d %d:%d\n", i, high[i], stk[top], high[stk[top]]);
			LL len = high[stk[top]] - max(high[stk[top-1]], high[i]);
			LL a = i-stk[top]+1;
			LL cnt = len*(a*(a+1)/2);
			//printf("?? %I64d %I64d\n", a, len);
			ans+=cnt;
			top--;
		}
		if(high[i]!=high[stk[top]]) stk[++top] = i;
//		printf("stk:: ");
//		for(int j=0;j<=top;j++){
//			printf("%d ", high[stk[j]]);
//		}puts("");
	}
	for(int i=1;i<=top;i++){
		LL len = high[stk[i]] - high[stk[i-1]];
		LL a = n-stk[i]+2;
		LL cnt = len*(a*(a+1)/2);
		//printf("?? %I64d %I64d\n", a, len);
		ans+=cnt;
	}
	printf("%I64d\n", ans+one);
}