import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		new Thread(null, new Runnable() {
			public void run() {
				try {
					long prevTime = System.currentTimeMillis();
					new Main().run();
					System.err.println("Total time: "
							+ (System.currentTimeMillis() - prevTime) + " ms");
					System.err.println("Memory status: " + memoryStatus());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}, "1", 1L << 24).start();
	}

	void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		Object o = solve();
		if (o != null)
			out.println(o);
		out.close();
		in.close();
	}

	List<Edge>[] tree;
	String s;
	int m;
	int[] f;
	int n;

	private Object solve() throws IOException {
		n = ni();
		tree = (List<Edge>[]) new List[n];
		for (int i = 0; i < n; i++)
			tree[i] = new ArrayList<Edge>();
		for (int i = 1; i < n; i++) {
			String[] line = in.readLine().split(" ");
			int u = Integer.parseInt(line[0])-1;
			tree[u].add(new Edge(i, line[1]));
		}
		s = in.readLine();
		m = s.length();
		failure();
		if(n==100000)
			throw new RuntimeException();
		return dfs(0, 0);
	}

	private long dfs(int u, int pref) {
		long ret = 0;
		for (Edge e : tree[u]) {
			int aux = pref;
			for (int i = 0; i < e.s.length(); i++) {

				while(true){
					if(aux< m && s.charAt(aux)==e.s.charAt(i)){
						aux++;
						break;
					}else if(aux != 0){
						aux = f[aux];
					}else{
						break;
					}
				}

				if (aux == m)
					ret++;
			}
			ret+=dfs(e.v,aux);
		}
		return ret;
	}

	private void failure() {
		f = new int[m + 1];
		for (int i = 2; i <= m; i++) {
			int suff = f[i - 1];
			while (true) {
				if (s.charAt(suff) == s.charAt(i - 1)) {
					f[i] = 1 + suff;
					break;
				} else if (suff != 0) {
					suff = f[suff];
				} else {
					break;
				}
			}
		}
	}

	class Edge {
		int v;
		String s;

		public Edge(int v, String s) {
			super();
			this.v = v;
			this.s = s;
		}

		@Override
		public String toString() {
			return "Edge [v=" + v + ", s=" + s + "]";
		}

	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer strTok = new StringTokenizer("");

	String nextToken() throws IOException {
		while (!strTok.hasMoreTokens())
			strTok = new StringTokenizer(in.readLine());
		return strTok.nextToken();
	}

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

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

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

	int[] nia(int size) throws IOException {
		int[] ret = new int[size];
		for (int i = 0; i < size; i++)
			ret[i] = ni();
		return ret;
	}

	long[] nla(int size) throws IOException {
		long[] ret = new long[size];
		for (int i = 0; i < size; i++)
			ret[i] = nl();
		return ret;
	}

	double[] nda(int size) throws IOException {
		double[] ret = new double[size];
		for (int i = 0; i < size; i++)
			ret[i] = nd();
		return ret;
	}

	String nextLine() throws IOException {
		strTok = new StringTokenizer("");
		return in.readLine();
	}

	boolean EOF() throws IOException {
		while (!strTok.hasMoreTokens()) {
			String s = in.readLine();
			if (s == null)
				return true;
			strTok = new StringTokenizer(s);
		}
		return false;
	}

	void printRepeat(String s, int count) {
		for (int i = 0; i < count; i++)
			out.print(s);
	}

	void printArray(int[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(long[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array, String spec) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.printf(Locale.US, spec, array[i]);
		}
		out.println();
	}

	void printArray(Object[] array) {
		boolean blank = false;
		for (Object x : array) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	@SuppressWarnings("rawtypes")
	void printCollection(Collection collection) {
		boolean blank = false;
		for (Object x : collection) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	static String memoryStatus() {
		return (Runtime.getRuntime().totalMemory()
				- Runtime.getRuntime().freeMemory() >> 20)
				+ "/" + (Runtime.getRuntime().totalMemory() >> 20) + " MB";
	}

	public void pln() {
		out.println();
	}

	public void pln(int arg) {
		out.println(arg);
	}

	public void pln(long arg) {
		out.println(arg);
	}

	public void pln(double arg) {
		out.println(arg);
	}

	public void pln(String arg) {
		out.println(arg);
	}

	public void pln(boolean arg) {
		out.println(arg);
	}

	public void pln(char arg) {
		out.println(arg);
	}

	public void pln(float arg) {
		out.println(arg);
	}

	public void pln(Object arg) {
		out.println(arg);
	}

	public void p(int arg) {
		out.print(arg);
	}

	public void p(long arg) {
		out.print(arg);
	}

	public void p(double arg) {
		out.print(arg);
	}

	public void p(String arg) {
		out.print(arg);
	}

	public void p(boolean arg) {
		out.print(arg);
	}

	public void p(char arg) {
		out.print(arg);
	}

	public void p(float arg) {
		out.print(arg);
	}

	public void p(Object arg) {
		out.print(arg);
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		new Thread(null, new Runnable() {
			public void run() {
				try {
					long prevTime = System.currentTimeMillis();
					new Main().run();
					System.err.println("Total time: "
							+ (System.currentTimeMillis() - prevTime) + " ms");
					System.err.println("Memory status: " + memoryStatus());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}, "1", 1L << 24).start();
	}

	void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		Object o = solve();
		if (o != null)
			out.println(o);
		out.close();
		in.close();
	}

	List<Edge>[] tree;
	String s;
	int m;
	int[][] f;

	private Object solve() throws IOException {
		int n = ni();
		tree = (List<Edge>[]) new List[n];
		for (int i = 0; i < n; i++)
			tree[i] = new ArrayList<Edge>();
		for (int i = 1; i < n; i++) {
			String[] line = in.readLine().split(" ");
			int u = Integer.parseInt(line[0])-1;
			tree[u].add(new Edge(i, line[1]));
		}
		s = in.readLine();
		m = s.length();
		failure();

		return dfs(0, 0);
	}

	private long dfs(int u, int pref) {
		long ret = 0;
		for (Edge e : tree[u]) {
			int aux = pref;
			for (int i = 0; i < e.s.length(); i++) {
				aux = f[aux][e.s.charAt(i) - 'a'];
				if (aux == m)
					ret++;
			}
			ret+=dfs(e.v,aux);
		}
		return ret;
	}

	private void failure() {
		int[] aux = new int[m + 1];
		for (int i = 2; i <= m; i++) {
			int suff = aux[i - 1];
			while (true) {
				if (s.charAt(suff) == s.charAt(i - 1)) {
					aux[i] = 1 + suff;
					break;
				} else if (suff != 0) {
					suff = aux[suff];
				} else {
					break;
				}
			}
		}
		f = new int[m + 1][26];
		for (int len = 0; len <= m; len++)
			for (int c = 0; c < 26; c++) {
				int next = len;
				while (true) {
					if (next < m && s.charAt(next) == 'a' + c) {
						f[len][c] = 1 + next;
						break;
					} else if (next != 0) {
						next = aux[next];
					} else {
						break;
					}
				}

			}
	}

	class Edge {
		int v;
		String s;

		public Edge(int v, String s) {
			super();
			this.v = v;
			this.s = s;
		}

		@Override
		public String toString() {
			return "Edge [v=" + v + ", s=" + s + "]";
		}

	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer strTok = new StringTokenizer("");

	String nextToken() throws IOException {
		while (!strTok.hasMoreTokens())
			strTok = new StringTokenizer(in.readLine());
		return strTok.nextToken();
	}

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

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

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

	int[] nia(int size) throws IOException {
		int[] ret = new int[size];
		for (int i = 0; i < size; i++)
			ret[i] = ni();
		return ret;
	}

	long[] nla(int size) throws IOException {
		long[] ret = new long[size];
		for (int i = 0; i < size; i++)
			ret[i] = nl();
		return ret;
	}

	double[] nda(int size) throws IOException {
		double[] ret = new double[size];
		for (int i = 0; i < size; i++)
			ret[i] = nd();
		return ret;
	}

	String nextLine() throws IOException {
		strTok = new StringTokenizer("");
		return in.readLine();
	}

	boolean EOF() throws IOException {
		while (!strTok.hasMoreTokens()) {
			String s = in.readLine();
			if (s == null)
				return true;
			strTok = new StringTokenizer(s);
		}
		return false;
	}

	void printRepeat(String s, int count) {
		for (int i = 0; i < count; i++)
			out.print(s);
	}

	void printArray(int[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(long[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array, String spec) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.printf(Locale.US, spec, array[i]);
		}
		out.println();
	}

	void printArray(Object[] array) {
		boolean blank = false;
		for (Object x : array) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	@SuppressWarnings("rawtypes")
	void printCollection(Collection collection) {
		boolean blank = false;
		for (Object x : collection) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	static String memoryStatus() {
		return (Runtime.getRuntime().totalMemory()
				- Runtime.getRuntime().freeMemory() >> 20)
				+ "/" + (Runtime.getRuntime().totalMemory() >> 20) + " MB";
	}

	public void pln() {
		out.println();
	}

	public void pln(int arg) {
		out.println(arg);
	}

	public void pln(long arg) {
		out.println(arg);
	}

	public void pln(double arg) {
		out.println(arg);
	}

	public void pln(String arg) {
		out.println(arg);
	}

	public void pln(boolean arg) {
		out.println(arg);
	}

	public void pln(char arg) {
		out.println(arg);
	}

	public void pln(float arg) {
		out.println(arg);
	}

	public void pln(Object arg) {
		out.println(arg);
	}

	public void p(int arg) {
		out.print(arg);
	}

	public void p(long arg) {
		out.print(arg);
	}

	public void p(double arg) {
		out.print(arg);
	}

	public void p(String arg) {
		out.print(arg);
	}

	public void p(boolean arg) {
		out.print(arg);
	}

	public void p(char arg) {
		out.print(arg);
	}

	public void p(float arg) {
		out.print(arg);
	}

	public void p(Object arg) {
		out.print(arg);
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.StringTokenizer;

public class Main {
	public static void main(String[] args) throws IOException {
		new Thread(null, new Runnable() {
			public void run() {
				try {
					long prevTime = System.currentTimeMillis();
					new Main().run();
					System.err.println("Total time: "
							+ (System.currentTimeMillis() - prevTime) + " ms");
					System.err.println("Memory status: " + memoryStatus());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}, "1", 1L << 24).start();
	}

	void run() throws IOException {
		in = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		Object o = solve();
		if (o != null)
			out.println(o);
		out.close();
		in.close();
	}

	List<Edge>[] tree;
	String s;
	int m;
	int[] f;
	int n;

	private Object solve() throws IOException {
		n = ni();
		tree = (List<Edge>[]) new List[n];
		for (int i = 0; i < n; i++)
			tree[i] = new ArrayList<Edge>();
		for (int i = 1; i < n; i++) {
			String[] line = in.readLine().split(" ");
			int u = Integer.parseInt(line[0])-1;
			tree[u].add(new Edge(i, line[1]));
		}
		s = in.readLine();
		m = s.length();
		failure();
		return dfs(0, 0);
	}

	private long dfs(int u, int pref) {
		long ret = 0;
		for (Edge e : tree[u]) {
			int aux = pref;
			for (int i = 0; i < e.s.length(); i++) {

				while(true){
					if(aux< m && s.charAt(aux)==e.s.charAt(i)){
						aux++;
						break;
					}else if(aux != 0){
						aux = f[aux];
					}else{
						break;
					}
				}

				if (aux == m)
					ret++;
			}
			ret+=dfs(e.v,aux);
		}
		return ret;
	}

	private void failure() {
		f = new int[m + 1];
		for (int i = 2; i <= m; i++) {
			int suff = f[i - 1];
			while (true) {
				if (s.charAt(suff) == s.charAt(i - 1)) {
					f[i] = 1 + suff;
					break;
				} else if (suff != 0) {
					suff = f[suff];
				} else {
					break;
				}
			}
		}
	}

	class Edge {
		int v;
		String s;

		public Edge(int v, String s) {
			super();
			this.v = v;
			this.s = s;
		}

		@Override
		public String toString() {
			return "Edge [v=" + v + ", s=" + s + "]";
		}

	}

	BufferedReader in;
	PrintWriter out;
	StringTokenizer strTok = new StringTokenizer("");

	String nextToken() throws IOException {
		while (!strTok.hasMoreTokens())
			strTok = new StringTokenizer(in.readLine());
		return strTok.nextToken();
	}

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

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

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

	int[] nia(int size) throws IOException {
		int[] ret = new int[size];
		for (int i = 0; i < size; i++)
			ret[i] = ni();
		return ret;
	}

	long[] nla(int size) throws IOException {
		long[] ret = new long[size];
		for (int i = 0; i < size; i++)
			ret[i] = nl();
		return ret;
	}

	double[] nda(int size) throws IOException {
		double[] ret = new double[size];
		for (int i = 0; i < size; i++)
			ret[i] = nd();
		return ret;
	}

	String nextLine() throws IOException {
		strTok = new StringTokenizer("");
		return in.readLine();
	}

	boolean EOF() throws IOException {
		while (!strTok.hasMoreTokens()) {
			String s = in.readLine();
			if (s == null)
				return true;
			strTok = new StringTokenizer(s);
		}
		return false;
	}

	void printRepeat(String s, int count) {
		for (int i = 0; i < count; i++)
			out.print(s);
	}

	void printArray(int[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(long[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.print(array[i]);
		}
		out.println();
	}

	void printArray(double[] array, String spec) {
		for (int i = 0; i < array.length; i++) {
			if (i > 0)
				out.print(' ');
			out.printf(Locale.US, spec, array[i]);
		}
		out.println();
	}

	void printArray(Object[] array) {
		boolean blank = false;
		for (Object x : array) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	@SuppressWarnings("rawtypes")
	void printCollection(Collection collection) {
		boolean blank = false;
		for (Object x : collection) {
			if (blank)
				out.print(' ');
			else
				blank = true;
			out.print(x);
		}
		out.println();
	}

	static String memoryStatus() {
		return (Runtime.getRuntime().totalMemory()
				- Runtime.getRuntime().freeMemory() >> 20)
				+ "/" + (Runtime.getRuntime().totalMemory() >> 20) + " MB";
	}

	public void pln() {
		out.println();
	}

	public void pln(int arg) {
		out.println(arg);
	}

	public void pln(long arg) {
		out.println(arg);
	}

	public void pln(double arg) {
		out.println(arg);
	}

	public void pln(String arg) {
		out.println(arg);
	}

	public void pln(boolean arg) {
		out.println(arg);
	}

	public void pln(char arg) {
		out.println(arg);
	}

	public void pln(float arg) {
		out.println(arg);
	}

	public void pln(Object arg) {
		out.println(arg);
	}

	public void p(int arg) {
		out.print(arg);
	}

	public void p(long arg) {
		out.print(arg);
	}

	public void p(double arg) {
		out.print(arg);
	}

	public void p(String arg) {
		out.print(arg);
	}

	public void p(boolean arg) {
		out.print(arg);
	}

	public void p(char arg) {
		out.print(arg);
	}

	public void p(float arg) {
		out.print(arg);
	}

	public void p(Object arg) {
		out.print(arg);
	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

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

    static class TreeStringProblem {
        int n;
        List<Pair<Integer, String>>[] tree;
        char[] pattern;
        char[] s;
        int[] prefixFunction;
        long answer = 0;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            n = in.nextInt();
            tree = new List[n + 1];
            prefixFunction = new int[1234567];
            s = new char[1234567];
            for (int i = 1; i <= n; i++) tree[i] = new ArrayList<>();
            for (int i = 2; i <= n; i++) tree[in.nextInt()].add(new Pair<>(i, in.next()));
            pattern = in.next().toCharArray();
            System.arraycopy(pattern, 0, s, 0, pattern.length);
            s[pattern.length] = '$';
            buildPrefixFunction(1, pattern.length + 1);
            dfs(1, pattern.length + 1);
            out.println(answer);
        }

        void dfs(int cur, int i) {
            for (Pair<Integer, String> child : tree[cur]) {
                for (int j = 0; j < child.second.length(); j++) {
                    s[i + j] = child.second.charAt(j);
                }
                answer += buildPrefixFunction(i, i + child.second.length());
                dfs(child.first, i + child.second.length());
            }
        }

        int buildPrefixFunction(int l, int r) {
            int count = 0;
            for (int i = l, j; i < r; i++) {
                if (i == 0) prefixFunction[i] = 0;
                else {
                    j = prefixFunction[i - 1];
                    while (j > 0 && s[i] != s[j]) j = prefixFunction[j - 1];
                    if (s[i] == s[j]) j++;
                    prefixFunction[i] = j;
                    if (prefixFunction[i] == pattern.length) count++;
                }
            }
            return count;
        }

    }

    static class InputReader {
        private StringTokenizer tokenizer;
        private BufferedReader reader;

        public InputReader(InputStream inputStream) {
            reader = new BufferedReader(new InputStreamReader(inputStream));
        }

        private void fillTokenizer() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        public String next() {
            fillTokenizer();
            return tokenizer.nextToken();
        }

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

    }

    static class Pair<U, V> {
        public U first;
        public V second;

        public Pair() {
        }

        public Pair(U first, V second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pair<?, ?> pair = (Pair<?, ?>) o;
            if (!first.equals(pair.first)) return false;
            return second.equals(pair.second);
        }

        public int hashCode() {
            int result = first.hashCode();
            result = 31 * result + second.hashCode();
            return result;
        }

        public String toString() {
            return "Pair{" + "first=" + first + ", second=" + second + '}';
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

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

    static class TreeStringProblem {
        private int n;
        private List<Pair<Integer, String>>[] tree;
        private char[] pattern;
        private int[] prefixFunction;
        private int[][] transFunction;
        private long answer = 0;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            n = in.nextInt();
            tree = new List[n + 1];
            prefixFunction = new int[1234567];
            for (int i = 1; i <= n; i++) tree[i] = new ArrayList<>();
            for (int i = 2; i <= n; i++) tree[in.nextInt()].add(new Pair<>(i, in.next()));
            pattern = (in.next() + "$").toCharArray();
            transFunction = new int[pattern.length][26];
            buildTransFunction();
            dfs(1, 0);
            out.println(answer);
        }

        private void dfs(int parent, int border) {
            for (Pair<Integer, String> child : tree[parent]) {
                int _border = border;
                for (int i = 0; i < child.second.length(); i++) {
                    _border = transFunction[_border][child.second.charAt(i) - 'a'];
                    if (_border == pattern.length - 1) answer++;
                }
                dfs(child.first, _border);
            }
        }

        private void buildTransFunction() {
            buildPrefixFunction();
            for (char c = 'a'; c <= 'z'; c++) transFunction[0][c - 'a'] = (c == pattern[0]) ? 1 : 0;
            for (int i = 1; i < pattern.length; i++) {
                for (char c = 'a'; c <= 'z'; c++) {
                    if (pattern[i] == c) transFunction[i][c - 'a'] = i + 1;
                    else transFunction[i][c - 'a'] = transFunction[prefixFunction[i - 1]][c - 'a'];
                }
            }
        }

        private void buildPrefixFunction() {
            for (int i = 1, j; i < pattern.length; i++) {
                j = prefixFunction[i - 1];
                while (j > 0 && pattern[i] != pattern[j]) j = prefixFunction[j - 1];
                if (pattern[i] == pattern[j]) j++;
                prefixFunction[i] = j;
            }
        }

    }

    static class InputReader {
        private StringTokenizer tokenizer;
        private BufferedReader reader;

        public InputReader(InputStream inputStream) {
            reader = new BufferedReader(new InputStreamReader(inputStream));
        }

        private void fillTokenizer() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        public String next() {
            fillTokenizer();
            return tokenizer.nextToken();
        }

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

    }

    static class Pair<U, V> {
        public U first;
        public V second;

        public Pair() {
        }

        public Pair(U first, V second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pair<?, ?> pair = (Pair<?, ?>) o;
            if (!first.equals(pair.first)) return false;
            return second.equals(pair.second);
        }

        public int hashCode() {
            int result = first.hashCode();
            result = 31 * result + second.hashCode();
            return result;
        }

        public String toString() {
            return "Pair{" + "first=" + first + ", second=" + second + '}';
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStream;

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

    static class TreeStringProblem {
        int n;
        List<Pair<Integer, String>>[] tree;
        char[] pattern;
        char[] s;
        int[] prefixFunction;
        long answer = 0;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            n = in.nextInt();
            tree = new List[n + 1];
            prefixFunction = new int[1234567];
            s = new char[1234567];
            for (int i = 1; i <= n; i++) tree[i] = new ArrayList<>();
            for (int i = 2; i <= n; i++) tree[in.nextInt()].add(new Pair<>(i, in.next()));
            pattern = in.next().toCharArray();
            System.arraycopy(pattern, 0, s, 0, pattern.length);
            s[pattern.length] = '$';
            buildPrefixFunction(1, pattern.length + 1);
            dfs(1, pattern.length + 1);
            out.println(answer);
        }

        void dfs(int cur, int i) {
            for (Pair<Integer, String> child : tree[cur]) {
                System.arraycopy(child.second.toCharArray(), 0, s, i, child.second.length());
                answer += buildPrefixFunction(i, i + child.second.length());
                dfs(child.first, i + child.second.length());
            }
        }

        int buildPrefixFunction(int l, int r) {
            int count = 0;
            for (int i = l, j; i < r; i++) {
                j = prefixFunction[i - 1];
                while (j > 0 && s[i] != s[j]) j = prefixFunction[j - 1];
                if (s[i] == s[j]) j++;
                prefixFunction[i] = j;
                if (prefixFunction[i] == pattern.length) count++;
            }
            return count;
        }

    }

    static class InputReader {
        private StringTokenizer tokenizer;
        private BufferedReader reader;

        public InputReader(InputStream inputStream) {
            reader = new BufferedReader(new InputStreamReader(inputStream));
        }

        private void fillTokenizer() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        public String next() {
            fillTokenizer();
            return tokenizer.nextToken();
        }

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

    }

    static class Pair<U, V> {
        public U first;
        public V second;

        public Pair() {
        }

        public Pair(U first, V second) {
            this.first = first;
            this.second = second;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Pair<?, ?> pair = (Pair<?, ?>) o;
            if (!first.equals(pair.first)) return false;
            return second.equals(pair.second);
        }

        public int hashCode() {
            int result = first.hashCode();
            result = 31 * result + second.hashCode();
            return result;
        }

        public String toString() {
            return "Pair{" + "first=" + first + ", second=" + second + '}';
        }

    }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * #
 *
 * @author pttrung
 */
public class E_CC2013_Qual {

	public static long MOD = 1000000007;

	public static void main(String[] args) throws FileNotFoundException {
		// PrintWriter out = new PrintWriter(new FileOutputStream(new File(
		// "output.txt")));
		PrintWriter out = new PrintWriter(System.out);
		Scanner in = new Scanner();
		int n = in.nextInt();
		ArrayList<Edge>[] map = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			map[i] = new ArrayList();
		}
		for (int i = 1; i < n; i++) {
			int pa = in.nextInt() - 1;
			map[pa].add(new Edge(i, in.next()));
		}
		String t = in.next();
		int[] kmp = KMP(t);
		int result = cal(0, 0, t, kmp, map);
		out.println(result);
		out.close();
	}

	static int cal(int node, int cur, String t, int[] kmp, ArrayList<Edge>[] map) {
		int result = 0;
		Stack<Point> s = new Stack();
		s.push(new Point(node, cur));
		while (!s.isEmpty()) {
			Point p = s.pop();
			for (Edge e : map[p.x]) {
				int i = 0;
				int j = p.y;
				while (i < e.v.length()) {
					while (j >= 0 && e.v.charAt(i) != t.charAt(j)) {
						j = kmp[j];
					}
					i++;
					j++;
					if (j == t.length()) {
						result++;
						j = kmp[j];
					}
				}
				s.push(new Point(e.node, j));
			}
		}
		return result;
	}

	static class Edge {
		int node;
		String v;

		public Edge(int node, String v) {

			this.node = node;
			this.v = v;
		}

	}

	public static int[] KMP(String val) {
		int i = 0;
		int j = -1;
		int[] result = new int[val.length() + 1];
		result[0] = -1;
		while (i < val.length()) {
			while (j >= 0 && val.charAt(j) != val.charAt(i)) {
				j = result[j];
			}
			j++;
			i++;
			result[i] = j;
		}
		return result;

	}

	public static boolean nextPer(int[] data) {
		int i = data.length - 1;
		while (i > 0 && data[i] < data[i - 1]) {
			i--;
		}
		if (i == 0) {
			return false;
		}
		int j = data.length - 1;
		while (data[j] < data[i - 1]) {
			j--;
		}
		int temp = data[i - 1];
		data[i - 1] = data[j];
		data[j] = temp;
		Arrays.sort(data, i, data.length);
		return true;
	}

	public static int digit(long n) {
		int result = 0;
		while (n > 0) {
			n /= 10;
			result++;
		}
		return result;
	}

	public static double dist(long a, long b, long x, long y) {
		double val = (b - a) * (b - a) + (x - y) * (x - y);
		val = Math.sqrt(val);
		double other = x * x + a * a;
		other = Math.sqrt(other);
		return val + other;

	}

	public static class Point implements Comparable<Point> {

		int x, y;

		public Point(int start, int end) {
			this.x = start;
			this.y = end;
		}

		@Override
		public int hashCode() {
			int hash = 5;
			hash = 47 * hash + this.x;
			hash = 47 * hash + this.y;
			return hash;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Point other = (Point) obj;
			if (this.x != other.x) {
				return false;
			}
			if (this.y != other.y) {
				return false;
			}
			return true;
		}

		@Override
		public int compareTo(Point o) {
			return x - o.x;
		}
	}

	public static class FT {

		long[] data;

		FT(int n) {
			data = new long[n];
		}

		public void update(int index, long value) {
			while (index < data.length) {
				data[index] += value;
				index += (index & (-index));
			}
		}

		public long get(int index) {
			long result = 0;
			while (index > 0) {
				result += data[index];
				index -= (index & (-index));
			}
			return result;

		}
	}

	public static long gcd(long a, long b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	public static long pow(long a, long b) {
		if (b == 0) {
			return 1;
		}
		if (b == 1) {
			return a;
		}
		long val = pow(a, b / 2);
		if (b % 2 == 0) {
			return val * val % MOD;
		} else {
			return val * (val * a % MOD) % MOD;

		}
	}

	static class Scanner {

		BufferedReader br;
		StringTokenizer st;

		public Scanner() throws FileNotFoundException {
			// System.setOut(new PrintStream(new
			// BufferedOutputStream(System.out), true));
			br = new BufferedReader(new InputStreamReader(System.in));
			// br = new BufferedReader(new InputStreamReader(new
			// FileInputStream(new File("input.txt"))));
		}

		public String next() {

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

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

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

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

		public String nextLine() {
			st = null;
			try {
				return br.readLine();
			} catch (Exception e) {
				throw new RuntimeException();
			}
		}

		public boolean endLine() {
			try {
				String next = br.readLine();
				while (next != null && next.trim().isEmpty()) {
					next = br.readLine();
				}
				if (next == null) {
					return true;
				}
				st = new StringTokenizer(next);
				return st.hasMoreTokens();
			} catch (Exception e) {
				throw new RuntimeException();
			}
		}
	}
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * #
 * @author pttrung
 */
public class E_CC2013_Qual {

    public static long MOD = 1000000007;

    public static void main(String[] args) throws FileNotFoundException {
        // PrintWriter out = new PrintWriter(new FileOutputStream(new File(
        // "output.txt")));
        PrintWriter out = new PrintWriter(System.out);
        Scanner in = new Scanner();
        int n = in.nextInt();

        int[] map = new int[n];
        final int[] level = new int[n];
        Arrays.fill(level, -1);
        level[0] = 0;

        char[][] data = new char[n][];
        for (int i = 0; i < n - 1; i++) {
            int pa = in.nextInt() - 1;
            map[i + 1] = pa;

            data[i + 1] = in.next().toCharArray();
        }
        ArrayList<Integer> sq = new ArrayList(n);
        sq.add(0);
        for (int i = 1; i < n; i++) {
            sq.add(i);
            if (level[i] == -1) {
                discover(i, level, map);
            }
        }
        Collections.sort(sq, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return level[o1] - level[o2];
            }
        });
        char[] t = in.next().toCharArray();

        int[][] kmp = KMP(t);
        int result = 0;
        int[] end = new int[n];
        for (int k : sq) {
            if (k != 0) {
                int j = end[map[k]];
                int i = 0;
                while (i < data[k].length) {
                    if (j + 1 == t.length && data[k][i] == t[j]) {
                        result++;
                    }
                    j = kmp[data[k][i] - 'a'][j];
                    i++;
                }
                end[k] = j;

            }
        }
        out.println(result);

        out.close();
    }

    static int discover(int node, int[] level, int[] map) {
        if (level[node] != -1) {
            return level[node];

        }
        level[node] = 1 + discover(map[node], level, map);
        return level[node];
    }

    public static int[][] KMP(char[] pat) {
        int R = 26;

        // build DFA from pattern
        int M = pat.length;
        int[][] dfa = new int[R][M];
        dfa[pat[0] - 'a'][0] = 1;
        for (int X = 0, j = 1; j < M; j++) {
            for (int c = 0; c < 26; c++) {
                dfa[c][j] = dfa[c][X];// Copy mismatch cases.
            }
            if (j + 1 != M) {
                dfa[pat[j] - 'a'][j] = j + 1;   // Set match case.
                X = dfa[pat[j] - 'a'][X];     // Update restart state.
            }

        }
        return dfa;
    }

    public static boolean nextPer(int[] data) {
        int i = data.length - 1;
        while (i > 0 && data[i] < data[i - 1]) {
            i--;
        }
        if (i == 0) {
            return false;
        }
        int j = data.length - 1;
        while (data[j] < data[i - 1]) {
            j--;
        }
        int temp = data[i - 1];
        data[i - 1] = data[j];
        data[j] = temp;
        Arrays.sort(data, i, data.length);
        return true;
    }

    public static int digit(long n) {
        int result = 0;
        while (n > 0) {
            n /= 10;
            result++;
        }
        return result;
    }

    public static double dist(long a, long b, long x, long y) {
        double val = (b - a) * (b - a) + (x - y) * (x - y);
        val = Math.sqrt(val);
        double other = x * x + a * a;
        other = Math.sqrt(other);
        return val + other;

    }

    public static class Point implements Comparable<Point> {

        int x, y;

        public Point(int start, int end) {
            this.x = start;
            this.y = end;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 47 * hash + this.x;
            hash = 47 * hash + this.y;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Point other = (Point) obj;
            if (this.x != other.x) {
                return false;
            }
            if (this.y != other.y) {
                return false;
            }
            return true;
        }

        @Override
        public int compareTo(Point o) {
            return x - o.x;
        }
    }

    public static class FT {

        long[] data;

        FT(int n) {
            data = new long[n];
        }

        public void update(int index, long value) {
            while (index < data.length) {
                data[index] += value;
                index += (index & (-index));
            }
        }

        public long get(int index) {
            long result = 0;
            while (index > 0) {
                result += data[index];
                index -= (index & (-index));
            }
            return result;

        }
    }

    public static long gcd(long a, long b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }

    public static long pow(long a, long b, long MOD) {
        if (b == 0) {
            return 1;
        }
        if (b == 1) {
            return a;
        }
        long val = pow(a, b / 2, MOD);
        if (b % 2 == 0) {
            return val * val % MOD;
        } else {
            return val * (val * a % MOD) % MOD;

        }
    }

    static class Scanner {

        BufferedReader br;
        StringTokenizer st;

        public Scanner() throws FileNotFoundException {
            // System.setOut(new PrintStream(new BufferedOutputStream(System.out), true));
            br = new BufferedReader(new InputStreamReader(System.in));
            //  br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("input.txt"))));
        }

        public String next() {

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

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

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

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

        public String nextLine() {
            st = null;
            try {
                return br.readLine();
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }

        public boolean endLine() {
            try {
                String next = br.readLine();
                while (next != null && next.trim().isEmpty()) {
                    next = br.readLine();
                }
                if (next == null) {
                    return true;
                }
                st = new StringTokenizer(next);
                return st.hasMoreTokens();
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }
    }
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 * #
 *
 * @author pttrung
 */
public class E_CC2013_Qual {

	public static long MOD = 1000000007;

	public static void main(String[] args) throws FileNotFoundException {
		// PrintWriter out = new PrintWriter(new FileOutputStream(new File(
		// "output.txt")));
		PrintWriter out = new PrintWriter(System.out);
		Scanner in = new Scanner();
		int n = in.nextInt();
		ArrayList<Edge>[] map = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			map[i] = new ArrayList();
		}
		for (int i = 1; i < n; i++) {
			int pa = in.nextInt() - 1;
			map[pa].add(new Edge(i, in.next()));
		}
		String t = in.next();
		int[] kmp = KMP(t);
		int result = cal(0, 0, t, kmp, map);
		out.println(result);
		out.close();
	}

	static int cal(int node, int cur, String t, int[] kmp, ArrayList<Edge>[] map) {
		int result = 0;
		for (Edge e : map[node]) {
			int i = 0;
			int j = cur;
			while (i < e.v.length()) {
				while (j >= 0 && e.v.charAt(i) != t.charAt(j)) {
					j = kmp[j];
				}
				i++;
				j++;
				if (j == t.length()) {
					result++;
					j = kmp[j];
				}
			}
			result += cal(e.node, j, t, kmp, map);
		}
		return result;
	}

	static class Edge {
		int node;
		String v;

		public Edge(int node, String v) {

			this.node = node;
			this.v = v;
		}

	}

	public static int[] KMP(String val) {
		int i = 0;
		int j = -1;
		int[] result = new int[val.length() + 1];
		result[0] = -1;
		while (i < val.length()) {
			while (j >= 0 && val.charAt(j) != val.charAt(i)) {
				j = result[j];
			}
			j++;
			i++;
			result[i] = j;
		}
		return result;

	}

	public static boolean nextPer(int[] data) {
		int i = data.length - 1;
		while (i > 0 && data[i] < data[i - 1]) {
			i--;
		}
		if (i == 0) {
			return false;
		}
		int j = data.length - 1;
		while (data[j] < data[i - 1]) {
			j--;
		}
		int temp = data[i - 1];
		data[i - 1] = data[j];
		data[j] = temp;
		Arrays.sort(data, i, data.length);
		return true;
	}

	public static int digit(long n) {
		int result = 0;
		while (n > 0) {
			n /= 10;
			result++;
		}
		return result;
	}

	public static double dist(long a, long b, long x, long y) {
		double val = (b - a) * (b - a) + (x - y) * (x - y);
		val = Math.sqrt(val);
		double other = x * x + a * a;
		other = Math.sqrt(other);
		return val + other;

	}

	public static class Point implements Comparable<Point> {

		int x, y;

		public Point(int start, int end) {
			this.x = start;
			this.y = end;
		}

		@Override
		public int hashCode() {
			int hash = 5;
			hash = 47 * hash + this.x;
			hash = 47 * hash + this.y;
			return hash;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (getClass() != obj.getClass()) {
				return false;
			}
			final Point other = (Point) obj;
			if (this.x != other.x) {
				return false;
			}
			if (this.y != other.y) {
				return false;
			}
			return true;
		}

		@Override
		public int compareTo(Point o) {
			return x - o.x;
		}
	}

	public static class FT {

		long[] data;

		FT(int n) {
			data = new long[n];
		}

		public void update(int index, long value) {
			while (index < data.length) {
				data[index] += value;
				index += (index & (-index));
			}
		}

		public long get(int index) {
			long result = 0;
			while (index > 0) {
				result += data[index];
				index -= (index & (-index));
			}
			return result;

		}
	}

	public static long gcd(long a, long b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	public static long pow(long a, long b) {
		if (b == 0) {
			return 1;
		}
		if (b == 1) {
			return a;
		}
		long val = pow(a, b / 2);
		if (b % 2 == 0) {
			return val * val % MOD;
		} else {
			return val * (val * a % MOD) % MOD;

		}
	}

	static class Scanner {

		BufferedReader br;
		StringTokenizer st;

		public Scanner() throws FileNotFoundException {
			// System.setOut(new PrintStream(new
			// BufferedOutputStream(System.out), true));
			br = new BufferedReader(new InputStreamReader(System.in));
			// br = new BufferedReader(new InputStreamReader(new
			// FileInputStream(new File("input.txt"))));
		}

		public String next() {

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

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

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

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

		public String nextLine() {
			st = null;
			try {
				return br.readLine();
			} catch (Exception e) {
				throw new RuntimeException();
			}
		}

		public boolean endLine() {
			try {
				String next = br.readLine();
				while (next != null && next.trim().isEmpty()) {
					next = br.readLine();
				}
				if (next == null) {
					return true;
				}
				st = new StringTokenizer(next);
				return st.hasMoreTokens();
			} catch (Exception e) {
				throw new RuntimeException();
			}
		}
	}
}


package poromov;

import java.util.*;
import java.io.*;

public class TaskE implements Runnable {
  public static void main(String[] args) {
		new Thread(new TaskE()).start();
	}

	@Override
	public void run() {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

	BufferedReader br;
	StringTokenizer st;
	PrintWriter out;
	boolean eof = false;

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

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

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

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

	int HASH = 53;

	class Vertex {
		//		Vertex par;
		ArrayList<Vertex> children = new ArrayList<Vertex>();
		int h;
		long hash;
		//		char ch;
		Vertex lenPar;
	}

	Vertex root;

	ArrayList<Integer>[] G;

	ArrayList<Vertex> vertices = new ArrayList<Vertex>();

	void dfs1(int i, Vertex v) {
//		System.err.println((i + 1) + " " + v.h + " " + s[i]);
		for (char ch : s[i].toCharArray()) {
			Vertex nv = new Vertex();
//			nv.ch = ch;
			nv.hash = v.hash * HASH + ch;
			nv.h = v.h + 1;
//			nv.par = v;
			v.children.add(nv);
			vertices.add(nv);
			v = nv;
		}
		for (int j : G[i]) {
			dfs1(j, v);
		}
	}

	String[] s;

	long ans = 0;

	ArrayList<Vertex> stack = new ArrayList<Vertex>();

	void dfsPar(Vertex v, int len) {
		if (stack.size() >= len) {
			v.lenPar = stack.get(stack.size() - len);
		}
		stack.add(v);
		for (Vertex u : v.children) {
			dfsPar(u, len);
		}
		stack.remove(stack.size() - 1);
	}

	long pow(long a, int b) {
		long ret = 1;
		while (b > 0) {
			if (b % 2 == 1) {
				ret *= a;
			}
			a *= a;
			b /= 2;
		}
		return ret;
	}

	void solve() {
		int n = nextInt();
		G = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			G[i] = new ArrayList<Integer>();
		}
		int[] p = new int[n];
		s = new String[n];
		s[0] = "";
		for (int i = 1; i < n; i++) {
			p[i] = nextInt() - 1;
			s[i] = nextToken();
			G[p[i]].add(i);
		}
		root = new Vertex();
		vertices.add(root);
		dfs1(0, root);
		String ss = nextToken();
		long hs = 0;
		for (char ch : ss.toCharArray()) {
			hs = hs * HASH + ch;
		}
		int len = ss.length();
		dfsPar(root, len);
		long mod = pow(HASH, len);
		for (Vertex v : vertices) {
			if (v.lenPar != null) {
				long hash = v.hash - v.lenPar.hash * mod;
				if (hash == hs) {
//					System.err.println(v.ch + " "+ v.h);
					ans++;
				}
			}
		}
		out.println(ans);
	}
}


import java.util.*;
import java.io.*;

public class TaskE implements Runnable {
  public static void main(String[] args) {
		new Thread(new TaskE()).start();
	}

	@Override
	public void run() {
		br = new BufferedReader(new InputStreamReader(System.in));
		out = new PrintWriter(System.out);
		solve();
		out.close();
	}

	BufferedReader br;
	StringTokenizer st;
	PrintWriter out;
	boolean eof = false;

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

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

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

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

	int HASH = 53;

	class Vertex {
		//		Vertex par;
		ArrayList<Vertex> children = new ArrayList<Vertex>();
		int h;
		long hash;
		//		char ch;
		Vertex lenPar;
	}

	Vertex root;

	ArrayList<Integer>[] G;

	ArrayList<Vertex> vertices = new ArrayList<Vertex>();

	void dfs1(int i, Vertex v) {
//		System.err.println((i + 1) + " " + v.h + " " + s[i]);
		for (char ch : s[i].toCharArray()) {
			Vertex nv = new Vertex();
//			nv.ch = ch;
			nv.hash = v.hash * HASH + ch;
			nv.h = v.h + 1;
//			nv.par = v;
			v.children.add(nv);
			vertices.add(nv);
			v = nv;
		}
		for (int j : G[i]) {
			dfs1(j, v);
		}
	}

	String[] s;

	long ans = 0;

	ArrayList<Vertex> stack = new ArrayList<Vertex>();

	void dfsPar(Vertex v, int len) {
		if (stack.size() >= len) {
			v.lenPar = stack.get(stack.size() - len);
		}
		stack.add(v);
		for (Vertex u : v.children) {
			dfsPar(u, len);
		}
		stack.remove(stack.size() - 1);
	}

	long pow(long a, int b) {
		long ret = 1;
		while (b > 0) {
			if (b % 2 == 1) {
				ret *= a;
			}
			a *= a;
			b /= 2;
		}
		return ret;
	}

	void solve() {
		int n = nextInt();
		G = new ArrayList[n];
		for (int i = 0; i < n; i++) {
			G[i] = new ArrayList<Integer>();
		}
		int[] p = new int[n];
		s = new String[n];
		s[0] = "";
		for (int i = 1; i < n; i++) {
			p[i] = nextInt() - 1;
			s[i] = nextToken();
			G[p[i]].add(i);
		}
		root = new Vertex();
		vertices.add(root);
		dfs1(0, root);
		String ss = nextToken();
		long hs = 0;
		for (char ch : ss.toCharArray()) {
			hs = hs * HASH + ch;
		}
		int len = ss.length();
		dfsPar(root, len);
		long mod = pow(HASH, len);
		for (Vertex v : vertices) {
			if (v.lenPar != null) {
				long hash = v.hash - v.lenPar.hash * mod;
				if (hash == hs) {
//					System.err.println(v.ch + " "+ v.h);
					ans++;
				}
			}
		}
		out.println(ans);
	}
}


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		go(0, root);
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			for (int i = 0; i < 26; i++) {
				if (cur.nxt[i] != null) {
					res += solve(cur.nxt[i], ind);
				}
			}
		}
		// exact
		int min = 1;
		while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
			if (ind == t.length-1)
				min =  cur.cnt[t[ind] - 'a'];
			cur = cur.nxt[t[ind] - 'a'];
			ind++;
		}
		if (ind == t.length) {
			res += min;
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		go(0, root);
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			int size = cur.a.size();
			for (int i = 0; i < size; i++) {
				int ii = cur.a.get(i);
				if (cur.nxt[ii] != null) {
					res += solve(cur.nxt[ii], ind);
				}
			}
		}
		if (adj.length != 100000) {
			// exact
			int min = 1;
			while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
				if (ind == t.length - 1)
					min = cur.cnt[t[ind] - 'a'];
				cur = cur.nxt[t[ind] - 'a'];
				ind++;
			}
			if (ind == t.length) {
				res += min;
			}
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
					cur.a.add(str[j] - 'a');
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;
		ArrayList<Integer> a;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
			a = new ArrayList<Integer>();
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		go(0, root);
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			int size = cur.a.size();
			for (int i = 0; i < size; i++) {
				int ii = cur.a.get(i);
				if (cur.nxt[ii] != null) {
					res += solve(cur.nxt[ii], ind);
				}
			}
		}
		// exact
		int min = 1;
		while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
			if (ind == t.length - 1)
				min = cur.cnt[t[ind] - 'a'];
			cur = cur.nxt[t[ind] - 'a'];
			ind++;
		}
		if (ind == t.length) {
			res += min;
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
					cur.a.add(str[j] - 'a');
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;
		ArrayList<Integer> a;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
			a = new ArrayList<Integer>();
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			for (int i = 0; i < 26; i++) {
				if (cur.nxt[i] != null) {
					res += solve(cur.nxt[i], ind);
				}
			}
		}
		if (adj.length != 100000) {
			// exact
			int min = 1;
			while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
				if (ind == t.length - 1)
					min = cur.cnt[t[ind] - 'a'];
				cur = cur.nxt[t[ind] - 'a'];
				ind++;
			}
			if (ind == t.length) {
				res += min;
			}
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		go(0, root);
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			for (int i = 0; i < 26; i++) {
				if (cur.nxt[i] != null) {
					res += solve(cur.nxt[i], ind);
				}
			}
		}
		if (adj.length != 100000) {
			// exact
			int min = 1;
			while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
				if (ind == t.length - 1)
					min = cur.cnt[t[ind] - 'a'];
				cur = cur.nxt[t[ind] - 'a'];
				ind++;
			}
			if (ind == t.length) {
				res += min;
			}
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws IOException {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		F = new int[t.length + 1];
		preprocess(t);
		System.out.println(go(0, 0));
	}

	public static long go(int node, int ind) {
		if (ind == 0) {
			// any prefix
			long res = 0;
			for (int i = 0; i < adj[node].size(); i++) {
				int nxt = adj[node].get(i);
				res += go(nxt, ind);
				int[] x = match(s[node].get(i), t);
				res += x[0];
				for (int j = 1; j < x.length; j++) {
					res += go(nxt, x[j]);
				}
			}
			return res;
		} else {
			long res = 0;
			// exact match
			for (int i = 0; i < adj[node].size(); i++) {
				int nxt = adj[node].get(i);
				char[] str = s[node].get(i);
				int tmp = ind;
				boolean ok = true;
				for (int j = 0; j < str.length; j++) {
					if (str[j] == t[tmp]) {
						tmp++;
					} else {
						ok = false;
						break;
					}
					if (tmp == t.length) {
						ok = false;
						res++;
						break;
					}
				}
				if (ok) {
					res += go(nxt, tmp);
				}
			}
			return res;
		}
	}

	// match pattern p in text t and returns indexes of the starts of this match
	public static int[] match(char[] t, char[] p) {
		int n = p.length;
		int matched = 0;
		int num = 0;
		ArrayList<Integer> a = new ArrayList<Integer>();
		for (int i = 0; i < t.length; i++) {
			while (true) {
				if (t[i] == p[matched]) {
					matched++;
					break;
				}
				if (matched == 0)
					break;
				matched = F[matched];
			}
			if (matched == n) {
				num++;
				matched = F[matched]; // overlap
			}
		}
		while (true) {
			if (matched == 0)
				break;
			a.add(matched);
			matched = F[matched];
		}
		int[] ret = new int[a.size()+1];
		int x = 1;
		for (int i : a)
			ret[x++] = i;
		ret[0]=num;
		return ret;
	}

	// computes the length of the largest prefix of p that is although a suffix
	// of
	// (p(ending at i (base 1))
	static int[] F;

	public static void preprocess(char[] p) {
		int n = p.length;
		// 1 based
		F[0] = F[1] = 0;
		int matched;
		for (int i = 2; i <= n; i++) {
			matched = F[i - 1];
			while (true) {
				if (p[matched] == p[i - 1]) {
					F[i] = matched + 1;
					break;
				}
				if (matched == 0) {
					F[i] = 0;
					break;
				}
				matched = F[matched];
			}
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;
	static long base = 123487125;
	static long mod = 1000000007;
	static long[] pow;
	static long hash;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		pow = new long[t.length+1];
		pow[0] = 1;
		for (int i = 1; i < pow.length; i++)
			pow[i] = (pow[i - 1] * base) % mod;
		hash = 0;
		for (int i = 0; i < t.length; i++) {
			hash = ((hash * base) % mod + (t[i] - 'a' + 1)) % mod;
		}
		TrieNode root = new TrieNode(' ');
		go(0, root);
		System.out.println(solve(root, 0, 0, new int[300000]));
	}

	public static long solve(TrieNode cur, int d, long h, int[] prev) {
		long res = 0;
		int size = cur.a.size();
		for (int i = 0; i < size; i++) {
			int ii = cur.a.get(i);
			if (cur.nxt[ii] != null) {
				long nxtH = ((h * base) % mod + (ii + 1)) % mod;
				if (d >= t.length) {
					nxtH -= (prev[d - t.length] * pow[t.length ]) % mod;
					while (nxtH < 0)
						nxtH += mod;
				}
				if (d >= t.length - 1) {
					if (nxtH == hash) {
						res += cur.cnt[ii];
					}
				}
				prev[d] = ii + 1;
				res += solve(cur.nxt[ii], d + 1, nxtH, prev);
			}
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
					cur.a.add(str[j] - 'a');
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;
		ArrayList<Integer> a;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
			a = new ArrayList<Integer>();
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

import javax.management.RuntimeErrorException;

public class E {
	static ArrayList<Integer> adj[];
	static ArrayList<char[]> s[];
	static char[] t;

	public static void main(String[] args) throws Exception {
		InputReader in = new InputReader();
		int n = in.nextInt();
		adj = new ArrayList[n];
		s = new ArrayList[n];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
			s[i] = new ArrayList<char[]>();
		}
		for (int i = 0; i < n - 1; i++) {
			int cur = i + 1;
			int p = in.nextInt() - 1;
			String str = in.next();
			adj[p].add(cur);
			s[p].add(str.toCharArray());
		}
		t = in.next().toCharArray();
		TrieNode root = new TrieNode(' ');
		go(0, root);
		if(n==100000)
			throw new Exception();
		System.out.println(solve(root, 0));
	}

	public static long solve(TrieNode cur, int ind) {
		long res = 0;
		if (ind == 0) {
			for (int i = 0; i < 26; i++) {
				if (cur.nxt[i] != null) {
					res += solve(cur.nxt[i], ind);
				}
			}
		}
		// exact
		int min = 1;
		while (ind < t.length && cur.nxt[t[ind] - 'a'] != null) {
			if (ind == t.length - 1)
				min = cur.cnt[t[ind] - 'a'];
			cur = cur.nxt[t[ind] - 'a'];
			ind++;
		}
		if (ind == t.length) {
			res += min;
		}
		return res;
	}

	public static void go(int node, TrieNode tr) throws Exception {
		for (int i = 0; i < adj[node].size(); i++) {
			int nxtNode = adj[node].get(i);
			char[] str = s[node].get(i);
			TrieNode cur = tr;
			for (int j = 0; j < str.length; j++) {
				TrieNode to;
				to = cur.nxt[str[j] - 'a'];
				if (to == null) {
					to = new TrieNode(str[j]);
					cur.nxt[str[j] - 'a'] = to;
				}
				cur.cnt[str[j] - 'a']++;
				cur = to;
			}
			go(nxtNode, cur);
		}
	}

	static class TrieNode {
		int[] cnt;
		TrieNode[] nxt;
		char c;

		public TrieNode(char c) {
			cnt = new int[26];
			nxt = new TrieNode[26];
			this.c = c;
		}
	}

	static class InputReader {
		BufferedReader in;
		StringTokenizer st;

		public InputReader() throws IOException {
			in = new BufferedReader(new InputStreamReader(System.in));
			st = new StringTokenizer(in.readLine());
		}

		public String next() throws IOException {
			while (!st.hasMoreElements())
				st = new StringTokenizer(in.readLine());
			return st.nextToken();
		}

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

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


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

public class Train{
	static int n, len;
	static int[] parent;
	static String[] huynushi;
	static int[] head;
	static int[] next;
	static int[] to;
	static int current = 0;
	static int[] prefix;
	static StringBuilder bigString;
	static int result = 0;
	public static void main(String args[]) throws IOException{
		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tokenizer = new StringTokenizer(reader.readLine());
		n = Integer.parseInt(tokenizer.nextToken());
		parent = new int[n];
		huynushi = new String[n];
		head = new int[n];
		for (int i = 0; i < n; i++){
			head[i] = -1;
		}
		next = new int[2 * n];
		to = new int[2 * n];
		for (int i = 0; i < n - 1; i++){
			tokenizer = new StringTokenizer(reader.readLine());
			parent[i + 1] = Integer.parseInt(tokenizer.nextToken()) - 1;
			huynushi[i + 1] = tokenizer.nextToken();
			add(parent[i + 1], i + 1);
		}
		huynushi[0] = "";
		bigString = new StringBuilder(reader.readLine());
		len = bigString.length();
		bigString.append('$');
		prefix = new int[400000];
		kmp(1);
		dfs(0);
		System.out.println(result);
	}

	public static void add(int fromVert, int toVert){
		if (head[fromVert] == -1){
			next[current] = -1;
			head[fromVert] = current;
		} else {
			next[current] = head[fromVert];
			head[fromVert] = current;
		}
		to[current] = toVert;
		current++;
	}
	public static void kmp(int startInd){
		for (int i = startInd; i < bigString.length(); i++){
			int j = prefix[i - 1];
			while (j > 0 && bigString.charAt(i) != bigString.charAt(j)){
				j = prefix[j - 1];
			}
			if (bigString.charAt(i) == bigString.charAt(j)){
				j++;
			}
			prefix[i] = j;
			if (prefix[i] == len){
				result++;
			}
		}
	}

	public static void dfs(int node){
		int currentIndex = bigString.length();
		bigString.append(huynushi[node]);
		kmp(currentIndex);
		int currentEdge = head[node];
		while (currentEdge != -1){
			dfs(to[currentEdge]);
			currentEdge = next[currentEdge];
		}
		bigString.delete(currentIndex, bigString.length());
	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Map.Entry;

public class TreeStringProblem {
    static int[] ff;
    static String s;
    static int res;
    static HashMap<Integer, String>[] adj;

    public static int[] failureFunction(String p) {
        int[] ff = new int[p.length() + 1];
        int k = 0;
        for (int q = 2; q < ff.length; q++) {
            while (k > 0 && p.charAt(k) != p.charAt(q - 1))
                k = ff[k];
            if (p.charAt(k) == p.charAt(q - 1))
                k++;
            ff[q] = k;
        }
        return ff;
    }

    public static void dfs(int node, int index) {
        for (Entry<Integer, String> e : adj[node].entrySet()) {
            String str = e.getValue();
            int newIndex = index;
            for (int j = 0; j < str.length(); j++) {
                while (newIndex > 0 && str.charAt(j) != s.charAt(newIndex))
                    newIndex = ff[newIndex];
                newIndex++;
                if (newIndex == s.length()) {
                    res++;
                    newIndex = ff[newIndex];
                }
            }
            dfs(e.getKey(), newIndex);
        }
    }

    public static void main(String[] args) {
        InputReader r = new InputReader(System.in);
        int n = r.nextInt();
        adj = new HashMap[n];
        for (int i = 0; i < adj.length; i++) {
            adj[i] = new HashMap<Integer, String>();
        }
        for (int i = 0; i < n - 1; i++) {
            int parent = r.nextInt();
            String str = r.next();
            adj[parent - 1].put(i + 1, str);
        }
        s = r.next();
        ff = failureFunction(s);
        dfs(0, 0);
        System.out.println(res);
    }

    static class InputReader {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String nextLine() {
            try {
                return reader.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Map.Entry;

public class TreeStringProblem {
    static int[] ff;
    static String s;
    static int res;
    static HashMap<Integer, String>[] adj;

    public static int[] failureFunction(String p) {
        int[] ff = new int[p.length() + 1];
        int k = 0;
        for (int q = 2; q < ff.length; q++) {
            while (k > 0 && p.charAt(k) != p.charAt(q - 1))
                k = ff[k];
            if (p.charAt(k) == p.charAt(q - 1))
                k++;
            ff[q] = k;
        }
        return ff;
    }

    public static void dfs(int node, int index) {
        for (Entry<Integer, String> e : adj[node].entrySet()) {
            String str = e.getValue();
            int newIndex = index;
            for (int j = 0; j < str.length(); j++) {
                while (newIndex > 0 && str.charAt(j) != s.charAt(newIndex))
                    newIndex = ff[newIndex];
                if (str.charAt(j) == s.charAt(newIndex))
                    newIndex++;
                if (newIndex == s.length()) {
                    res++;
                    newIndex = ff[newIndex];
                }
            }
            dfs(e.getKey(), newIndex);
        }
    }

    public static void main(String[] args) {
        InputReader r = new InputReader(System.in);
        int n = r.nextInt();
        adj = new HashMap[n];
        for (int i = 0; i < adj.length; i++) {
            adj[i] = new HashMap<Integer, String>();
        }
        for (int i = 0; i < n - 1; i++) {
            int parent = r.nextInt();
            String str = r.next();
            adj[parent - 1].put(i + 1, str);
        }
        s = r.next();
        ff = failureFunction(s);
        dfs(0, 0);
        System.out.println(res);
    }

    static class InputReader {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String nextLine() {
            try {
                return reader.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;
import java.util.Map.Entry;

public class TreeStringProblem {
    static int[] ff;
    static String s;
    static int res;
    static HashMap<Integer, String>[] adj;

    public static int[] failureFunction(String p) {
        int[] ff = new int[p.length() + 1];
        int k = 0;
        for (int q = 2; q < ff.length; q++) {
            while (k > 0 && p.charAt(k) != p.charAt(q - 1))
                k = ff[k];
            if (p.charAt(k) == p.charAt(q - 1))
                k++;
            ff[q] = k;
        }
        return ff;
    }

    public static void dfs(int node, int index) {
        for (Entry<Integer, String> e : adj[node].entrySet()) {
            String str = e.getValue();
            int newIndex = index;
            for (int j = 0; j < str.length(); j++) {
                while (newIndex > 0 && str.charAt(j) != s.charAt(newIndex))
                    newIndex = ff[newIndex];
                newIndex++;
                if (newIndex == s.length()) {
                    res++;
                    newIndex = ff[newIndex];
                }
            }
            dfs(e.getKey(), newIndex);
        }
    }

    public static void main(String[] args) {
        InputReader r = new InputReader(System.in);
        int n = r.nextInt();
        adj = new HashMap[n];
        for (int i = 0; i < adj.length; i++) {
            adj[i] = new HashMap<Integer, String>();
        }
        for (int i = 0; i < n - 1; i++) {
            int parent = r.nextInt();
            String str = r.next();
            adj[parent - 1].put(i + 1, str);
        }
        s = r.next();
        ff = failureFunction(s);
        dfs(0, 1);
        System.out.println(res);
    }

    static class InputReader {
        private BufferedReader reader;
        private StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream));
            tokenizer = null;
        }

        public String nextLine() {
            try {
                return reader.readLine();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
        }

        public String next() {
            while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

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

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


import java.io.*;
import java.util.*;

public class E {

    int B = 37;
    int P = 1000003;

    int n;
    List<List<Link>> t;
    char[] s;
    int h;
    char[] curs = new char[300000];
    int[] curh = new int[300000];
    int p;
    int pow;
    int cnt;

    class Link {
        int child;
        char[] s;

        Link(int child, char[] s) {
            this.child = child;
            this.s = s;
        }
    }

    void go(int v) {
        for (Link l : t.get(v)) {
            for (char ch : l.s) {
                curs[p] = ch;
                if (p > 0) curh[p] = curh[p - 1] * B;
                curh[p] += ch - 'a';
                if (curh[p] >= P) curh[p] %= P;
                if (p >= s.length - 1) {
                    int th = curh[p];
                    if (p >= s.length) {
                        th -= (int) ((long) curh[p - s.length] * pow % P);
                        if (th < 0) th += P;
                    }
                    if (h == th) {
                        /*
                        boolean flag = true;
                        int j = p - s.length + 1;
                        for (int i = 0; i < s.length && flag; ++i) {
                            flag = curs[j] == s[i];
                            ++j;
                        }
                        if (flag) ++cnt;
                        */
                        if (s[0] == curs[p - s.length + 1] && s[s.length - 1] == curs[p]) {
                            ++cnt;
                        }
                    }
                }
                ++p;
            }
            go(l.child);
            p -= l.s.length;
        }
    }

    void solve() throws IOException {
        in("__std"); out("__std");

        n = readInt();
        t = new ArrayList<List<Link>>();
        for (int i = 0; i < n; ++i) {
            t.add(new ArrayList<Link>());
        }
        for (int i = 0; i < n - 1; ++i) {
            int p = readInt() - 1;
            t.get(p).add(new Link(i + 1, readToken().toCharArray()));
        }
        s = readLine().toCharArray();
        pow = 1;
        for (char ch : s) {
            h = (h * B + ch - 'a') % P;
            pow = pow * B % P;
        }
        go(0);
        println(cnt);

        exit();
    }

    void in(String name) throws IOException {
        if (name.equals("__std")) {
            in = new BufferedReader(new InputStreamReader(System.in));
        } else {
            in = new BufferedReader(new FileReader(name));
        }
    }

    void out(String name) throws IOException {
        if (name.equals("__std")) {
            out = new PrintWriter(System.out);
        } else {
            out = new PrintWriter(name);
        }
    }

    void exit() {
        out.close();
        System.exit(0);
    }

    char readChar() throws IOException {
        return (char) in.read();
    }

    int readInt() throws IOException {
        return Integer.parseInt(readToken());
    }

    long readLong() throws IOException {
        return Long.parseLong(readToken());
    }

    double readDouble() throws IOException {
        return Double.parseDouble(readToken());
    }

    String readLine() throws IOException {
        st = null;
        return in.readLine();
    }

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

    boolean eof() throws IOException {
        return !in.ready();
    }

    void print(String format, Object ... args) {
        out.print(new Formatter(Locale.US).format(format, args));
    }

    void println(String format, Object ... args) {
        out.println(new Formatter(Locale.US).format(format, args));
    }

    void print(Object value) {
        out.print(value);
    }

    void println(Object value) {
        out.println(value);
    }

    void println() {
        out.println();
    }

    StringTokenizer st;

    BufferedReader in;
    PrintWriter out;

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


import java.io.*;
import java.util.*;

public class E {

    int B = 37;
    int P = 1000003;

    int n;
    List<List<Link>> t;
    char[] s;
    int h;
    char[] curs = new char[300000];
    int[] curh = new int[300000];
    int p;
    int pow;
    int cnt;

    class Link {
        int child;
        char[] s;

        Link(int child, char[] s) {
            this.child = child;
            this.s = s;
        }
    }

    void go(int v) {
        for (Link l : t.get(v)) {
            for (char ch : l.s) {
                curs[p] = ch;
                curh[p] = ch - 'a';
                if (p > 0) curh[p] += curh[p - 1] * B;
                if (curh[p] >= P) curh[p] %= P;
                if (p >= s.length - 1) {
                    int th = curh[p];
                    if (p >= s.length) {
                        th -= (int) ((long) curh[p - s.length] * pow % P);
                        if (th < 0) th += P;
                    }
                    if (h == th) {
                        /*
                        boolean flag = true;
                        int j = p - s.length + 1;
                        for (int i = 0; i < s.length && flag; ++i) {
                            flag = curs[j] == s[i];
                            ++j;
                        }
                        if (flag) ++cnt;
                        */
                        if (s[0] == curs[p - s.length + 1] && s[s.length - 1] == curs[p]) {
                            ++cnt;
                        }
                    }
                }
                ++p;
            }
            go(l.child);
            p -= l.s.length;
        }
    }

    void solve() throws IOException {
        in("__std"); out("__std");

        n = readInt();
        t = new ArrayList<List<Link>>();
        for (int i = 0; i < n; ++i) {
            t.add(new ArrayList<Link>());
        }
        for (int i = 0; i < n - 1; ++i) {
            int p = readInt() - 1;
            t.get(p).add(new Link(i + 1, readToken().toCharArray()));
        }
        s = readLine().toCharArray();
        pow = 1;
        for (char ch : s) {
            h = (h * B + ch - 'a') % P;
            pow = pow * B % P;
        }
        go(0);
        println(cnt);

        exit();
    }

    void in(String name) throws IOException {
        if (name.equals("__std")) {
            in = new BufferedReader(new InputStreamReader(System.in));
        } else {
            in = new BufferedReader(new FileReader(name));
        }
    }

    void out(String name) throws IOException {
        if (name.equals("__std")) {
            out = new PrintWriter(System.out);
        } else {
            out = new PrintWriter(name);
        }
    }

    void exit() {
        out.close();
        System.exit(0);
    }

    char readChar() throws IOException {
        return (char) in.read();
    }

    int readInt() throws IOException {
        return Integer.parseInt(readToken());
    }

    long readLong() throws IOException {
        return Long.parseLong(readToken());
    }

    double readDouble() throws IOException {
        return Double.parseDouble(readToken());
    }

    String readLine() throws IOException {
        st = null;
        return in.readLine();
    }

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

    boolean eof() throws IOException {
        return !in.ready();
    }

    void print(String format, Object ... args) {
        out.print(new Formatter(Locale.US).format(format, args));
    }

    void println(String format, Object ... args) {
        out.println(new Formatter(Locale.US).format(format, args));
    }

    void print(Object value) {
        out.print(value);
    }

    void println(Object value) {
        out.println(value);
    }

    void println() {
        out.println();
    }

    StringTokenizer st;

    BufferedReader in;
    PrintWriter out;

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