#ifdef DEBUG
#define _GLIBCXX_DEBUG
#endif

#include <bits/stdc++.h>

using namespace std;

mt19937 mrand(random_device{} ());

int rnd(int x) {
  return mrand() % x;
}

typedef long double ld;
typedef long long ll;

#ifdef DEBUG
#define eprintf(...) fprintf(stderr, __VA_ARGS__), fflush(stderr)
#else
#define eprintf(...) ;
#endif

#define pb push_back
#define mp make_pair
#define sz(x) ((int) (x).size())
#define TASK "text"

const int inf = (int) 1.01e9;
const ld eps = 1e-9;
const ld pi = acos((ld) -1.0);

void precalc() {
}

struct point3 {
  ld x, y, z;

  int read() {
    double x_, y_, z_;
    if (scanf("%lf%lf%lf", &x_, &y_, &z_) < 3) {
      return 0;
    }
    x = x_, y = y_, z = z_;
    return 1;
  }

  point3() {}
  point3(ld x_, ld y_, ld z_) : x(x_), y(y_), z(z_) {}

  point3 operator - (const point3 &p) const {
    return point3(x - p.x, y - p.y, z - p.z);
  }

  point3 operator + (const point3 &p) const {
    return point3(x + p.x, y + p.y, z + p.z);
  }

  point3 operator ^ (const point3 &p) const {
    return point3(y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x);
  }

  point3 operator * (const ld &k) const {
    return point3(x * k, y * k, z * k);
  }

  ld operator * (const point3 &p) const {
    return x * p.x + y * p.y + z * p.z;
  }

  ld slen() const {
    return *this * *this;
  }

  ld len() const {
    return sqrt(slen());
  }
};

int sgn(ld x) {
  return x < -eps ? -1 : x > eps;
}

const int maxn = (int) 1e5 + 10;

int ns[2];
point3 ps[2][maxn];

int n;

int read() {
  for (int it = 0; it < 2; ++it) {
    int &n = ns[it];
    if (scanf("%d", &n) < 1) {
      return 0;
    }
    for (int i = 0; i < n; ++i) {
      assert(ps[it][i].read());
    }
  }
  return 1;
}

struct point {
  ld x, y;

  const char *str() const {
    char *ans = new char[30];
    sprintf(ans, "(%.3f,%.3f)", (double) x, (double) y);
    return ans;
  }

  point() {}
  point(ld x_, ld y_) : x(x_), y(y_) {}

  point operator - (const point &p) const {
    return point(x - p.x, y - p.y);
  }

  point operator + (const point &p) const {
    return point(x + p.x, y + p.y);
  }

  ld operator ^ (const point &p) const {
    return x * p.y - y * p.x;
  }

  bool operator < (const point &p) const {
    if (abs(x - p.x) > eps) {
      return x < p.x;
    }
    return y < p.y - eps;
  }
};

point qs[maxn];

ld gety(int id, ld x) {
  return qs[id].y + (qs[id + 1].y - qs[id].y) * (x - qs[id].x) / (qs[id + 1].x - qs[id].x);
}

struct sComp {
  static ld x;

  inline bool operator () (const int a, const int b) const {
    ld diff = gety(a, x) - gety(b, x);
    return diff < 0;
  }
};
ld sComp::x;

pair<point, int> qqs[maxn];

pair<ld, pair<int, int> > evs[maxn * 2];

bool iseq(int n, point *ps, int cnt, pair<point, int> *qs) {
  {
    ld alf = (ld) rnd((int) 1e9) / 1e9 * pi;
    ld a = cos(alf), b = sin(alf);
    for (int i = 0; i < n; ++i) {
      auto &p = ps[i];
      p = point(p.x * a - p.y * b, p.x * b + p.y * a);
    }
    for (int i = 0; i < cnt; ++i) {
      auto &p = qs[i].first;
      p = point(p.x * a - p.y * b, p.x * b + p.y * a);
    }
  }
  assert(n <= maxn && cnt <= maxn);
  ps[n] = ps[0];
  {
    ld S = 0;
    for (int i = 0; i < n; ++i) {
      S += ps[i] ^ ps[i + 1];
    }
    if (S < 0) {
      reverse(ps, ps + n + 1);
    }
  }

  /*for (int i = 0; i < n; ++i) {
    eprintf("%s%c", ps[i].str(), " \n"[i == n - 1]);
  }
  for (int i = 0; i < cnt; ++i) {
    eprintf("(%s,%d)%c", qs[i].first.str(), qs[i].second, " \n"[i == cnt - 1]);
  }*/

  sort(qs, qs + cnt);

  int m = 0;
  for (int i = 0; i < n; ++i) {
    auto a = ps[i], b = ps[i + 1];
    if (abs(a.x - b.x) < eps) {
      continue;
    }
    if (b < a) {
      swap(a, b);
    }
    evs[m++] = mp(a.x + eps / 2, mp(1, i));
    evs[m++] = mp(b.x, mp(-1, i));
  }
  sort(evs, evs + m);

  int bal = 0;
  set<int, sComp> tree;

  for (int i = 0, j = 0; i < cnt; ++i) {
    while (j < m && evs[j].first < qs[i].first.x - eps) {
      sComp::x = evs[j].first;

      int type = evs[j].second.first, id = evs[j].second.second;
      if (type == 1) {
        tree.insert(id);
      } else {
        tree.erase(id);
      }

      ++j;
    }

    sComp::x = qs[i].first.x;
    ps[n + 2] = qs[i].first, ps[n + 3] = ps[n + 2] + point(1, 0);
    auto iter = tree.lower_bound(n + 2);
    if (iter != tree.end() && ps[*iter].x > ps[*iter + 1].x) {
      //eprintf("*iter = %d\n", *iter);
      bal += qs[i].second;
    }
  }
  //eprintf("bal = %d\n", bal);
  return !bal;
}

void solve() {
  for (int rot = 0; rot < 2; ++rot) {
    point3 p0 = ps[0][0];
    point3 x = ps[0][1] - p0, y = ps[0][2] - p0;
    point3 norm = x ^ y;
    norm = norm * (1 / norm.len());
    x = x * (1 / x.len());
    y = x ^ norm;
    for (int i = 0; i < ns[0]; ++i) {
      qs[i] = point(ps[0][i] * x, ps[0][i] * y);
    }

    int cnt = 0;
    ps[1][ns[1]] = ps[1][0];
    for (int i = 0; i < ns[1]; ++i) {
      point3 a = ps[1][i], b = ps[1][i + 1];
      int s1 = sgn((a - p0) * norm), s2 = sgn((b - p0) * norm);
      int type = 1;
      if (s1 > s2) {
        type = -1;
        swap(s1, s2);
      }
      if (s1 <= 0 && s2 > 0) {
        point3 q = a + ((b - a) * (((p0 - a) * norm) / ((b - a) * norm)));
        point p(q * x, q * y);
        qqs[cnt++] = mp(p, type);
      }
    }

    if (!iseq(ns[0], qs, cnt, qqs)) {
      printf("YES\n");
      return;
    }
    swap(ps[0], ps[1]);
    swap(ns[0], ns[1]);
  }
  printf("NO\n");
}

int main() {
  precalc();
#ifdef LOCAL
  freopen(TASK ".out", "w", stdout);
  assert(freopen(TASK ".in", "r", stdin));
#endif

  while (1) {
    if (!read()) {
      break;
    }
    solve();
#ifdef DEBUG
    eprintf("Time %.2f\n", (double) clock() / CLOCKS_PER_SEC);
#endif
  }
  return 0;
}


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdint>
#include <iostream>
#include <vector>

template <typename T>
inline T read_uint(T &x) {
    x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') { ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x;
}

inline double read_double() {
    int_fast64_t f = 1, x = 0;
    char ch = getchar();
    while(ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    x = x * f;
    return (double) x;
}

const double EPS = 1e-10;

class Point {
public:
    Point() = default;
    Point(double x, double y, double z) : x(x), y(y), z(z) {}
    Point(const Point &rhs) {
        x = rhs.x;
        y = rhs.y;
        z = rhs.z;
    }
    Point& operator=(const Point &rhs) {
        if(this == &rhs)
            return *this;
        x = rhs.x;
        y = rhs.y;
        z = rhs.z;
        return *this;
    }
    double length() const { return sqrt(x * x + y * y + z * z); }
    void normalize() {
        double l = length();
        x /= l;
        y /= l;
        z /= l;
    }
    virtual ~Point() = default;
    Point cross(const Point &rhs) const {
        double new_x = y * rhs.z - z * rhs.y;
        double new_y = z * rhs.x - x * rhs.z;
        double new_z = x * rhs.y - y * rhs.x;
        return Point(new_x, new_y, new_z);
    }
    double dot(const Point &rhs) const {
        return x * rhs.x + y * rhs.y + z * rhs.z;
    }
    Point operator+(const Point &rhs) const {
        double new_x = x + rhs.x;
        double new_y = y + rhs.y;
        double new_z = z + rhs.z;
        return Point(new_x, new_y, new_z);
    }
    Point operator-(const Point &rhs) const {
        double new_x = x - rhs.x;
        double new_y = y - rhs.y;
        double new_z = z - rhs.z;
        return Point(new_x, new_y, new_z);
    }
    Point& operator+=(const Point &rhs) {
        x += rhs.x;
        y += rhs.y;
        z += rhs.z;
        return *this;
    }
    Point& operator-=(const Point &rhs) {
        x -= rhs.x;
        y -= rhs.y;
        z -= rhs.z;
        return *this;
    }
    friend std::ostream& operator<< (std::ostream &os, const Point &p) {
        os << "Point{x=" << p.x << ", y=" << p.y << ", z=" << p.z << "}";
        return os;
    }
    double get_x() const { return x; }
    double get_y() const { return y; }
    double get_z() const { return z; }
private:
    double x;
    double y;
    double z;
};

class Line {
public:
    Line(Point begin, Point end) {
        a = end.get_y() - begin.get_y();
        b = begin.get_x() - end.get_x();
        c = - (a * begin.get_x() + b * begin.get_y());
    }
    virtual ~Line() = default;
    double distance(const Point &p) const { return a * p.get_x() + b * p.get_y() + c; }
    Point intersect(const Line &rhs) const {
        double d = a * rhs.b - b * rhs.a;
        double dx = (-c) * rhs.b - b * (-rhs.c);
        double dy = a * (-rhs.c) - (-c) * rhs.a;
        return Point(dx / d, dy / d, 0);
    }
    double get_a() const { return a; }
    double get_b() const { return b; }
    double get_c() const { return c; }
private:
    double a;
    double b;
    double c;
};

class Event {
public:
    Event(const Point &p, int type) : p(p), type(type) {}
    virtual ~Event() = default;
    const Point& get_p() const { return p; }
    int get_type() const { return type; }
private:
    Point p;
    int type;
};

double dist(const Point &p, const Point &origin, const Point &norm) {
    return (p - origin).dot(norm);
}

Point project(const Point &p, const Point &origin, const Point &v1, const Point &v2) {
    Point vec = p - origin;
    return Point(vec.dot(v1), vec.dot(v2), 0);
}

int main(int argc, char *argv[]) {
    using namespace std;
    double xtmp, ytmp, ztmp;
    uint_fast32_t nn; read_uint(nn);
    vector<Point> a;
    a.reserve(nn);
    uint_fast32_t i;
    for (i = 0; i < nn; i++) {
        xtmp = read_double();
        ytmp = read_double();
        ztmp = read_double();
        a.push_back(Point(xtmp, ytmp, ztmp));
    }
    uint_fast32_t mm; read_uint(mm);
    vector<Point> b;
    b.reserve(nn);
    for (i = 0; i < mm; i++) {
        xtmp = read_double();
        ytmp = read_double();
        ztmp = read_double();
        b.push_back(Point(xtmp, ytmp, ztmp));
    }
    for (i = 1; i < nn; i++) {
        a[i] -= a[0];
    }
    for (i = 0; i < mm; i++) {
        b[i] -= a[0];
    }
    a[0] = Point(0.0, 0.0, 0.0);

    Point v1 = a[nn - 1] - a[0];
    Point v2 = a[1] - a[0];
    Point norm = v1.cross(v2);
    norm.normalize();
    v1.normalize();
    v2 = norm.cross(v1);
    v2.normalize();

    bool same_plane = true;
    for (i = 0; i < mm; i++) {
        double or_dist = (b[i] - a[0]).dot(norm);
        if (abs(or_dist) > EPS) {
            same_plane = false;
        }
    }
    if (same_plane) {
        cout << "NO\n";
        return 0;
    }

    vector<Event> events;
    for (i = 0; i < mm; i++) {
        Point first = b[i];
        Point second = b[(i + 1) % b.size()];

        double dist1 = dist(first, a[0], norm);
        double dist2 = dist(second, a[0], norm);

        bool swap = false;
        if (dist1 > dist2) {
            swap = true;
            double tmp = dist1;
            dist1 = dist2;
            dist2 = tmp;

            Point tmpp = first;
            first = second;
            second = tmpp;
        }

        if (dist1 <= EPS && dist2 > EPS) {
            double ratio = (0 - dist1) / (dist2 - dist1);

            Point inter(first.get_x() * (1 - ratio) + second.get_x() * ratio,
                        first.get_y() * (1 - ratio) + second.get_y() * ratio,
                        first.get_z() * (1 - ratio) + second.get_z() * ratio);
            inter = project(inter, a[0], v1, v2);
            events.push_back(Event(inter, swap ? 1 : -1));
        }
    }

    if (events.size() == 0) {
        cout << "NO\n";
        return 0;
    }

    Line line(events[0].get_p(), events[1].get_p());

    for (i = 1; i < nn; i++) {
        a[i] = project(a[i], a[0], v1, v2);
    }
    a[0] = Point(0, 0, 0);

    for (i = 0; i < nn; i++) {
        Point first = a[i], second = a[(i + 1) % nn];
        double dist1 = line.distance(first);
        double dist2 = line.distance(second);
        if (dist1 > dist2) {
            double tmp = dist1;
            dist1 = dist2;
            dist2 = tmp;
        }
        if (dist1 <= EPS && EPS < dist2) {
            Line second_line(first, second);
            Point inter = line.intersect(second_line);
            events.push_back(Event(inter, 0));
        }
    }
    const Point direction(-line.get_b(), line.get_a(), 0);
    sort(events.begin(), events.end(), [direction] (const Event &a, const Event & b) -> bool {
        return direction.dot(a.get_p()) < direction.dot(b.get_p());
    });
    int result = 0;
    bool inside = false;
    for (auto &e : events) {
        if (e.get_type() == 0) {
            inside ^= true;
        } else {
            if (inside) {
                result += e.get_type();
            }
        }
    }
    cout << (result == 0 ? "NO\n" : "YES\n");
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
using LD = long double;
constexpr int maxn = 120000;
constexpr LD eps = 1e-10;
int sgn(LD x){
	if(x <= -eps) return -1;
	if(x >= eps) return 1;
	return 0;
}
struct P{
	LD x, y, z;
	P(LD x = 0, LD y = 0, LD z = 0): x(x), y(y), z(z){};
}p[2][maxn], n[2];
LD operator * (P A, P B){return A.x * B.x + A.y * B.y + A.z * B.z;}
P operator + (P A, P B){return P(A.x + B.x, A.y + B.y, A.z + B.z);}
P operator - (P A, P B){return P(A.x - B.x, A.y - B.y, A.z - B.z);}
P operator * (P A, LD k){return P(A.x * k, A.y * k, A.z * k);}
P cross(P A, P B){return P(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);}
int m[2], mix[maxn];
int main(){
	ios::sync_with_stdio(false);
	for(int t = 0; t < 2; t += 1){
		cin >> m[t];
		for(int i = 0; i < m[t]; i += 1) cin >> p[t][i].x >> p[t][i].y >> p[t][i].z;
		p[t][m[t]] = p[t][0];
		n[t] = cross(p[t][1] - p[t][0], p[t][2] - p[t][0]);
	}
	if(sgn(cross(n[0], n[1]) * cross(n[0], n[1])) == 0){
		cout << "NO";
		return 0;
	}
	P X = cross(n[0], n[1]);
	vector<pair<double, pair<int, int>>> v;
	for(int t = 0; t < 2; t += 1){
		for(int i = 0; i <= m[t]; i += 1) mix[i] = sgn(p[t][i] * n[t ^ 1]);
		for(int i = 0; i < m[t]; i += 1){
			if(mix[i] == mix[i + 1]) continue;
			v.push_back(make_pair(X * p[t][i], make_pair(t, (mix[i] - mix[i + 1]) * 2)));
		}
	}
	sort(v.begin(), v.end());
	int sgn = 0, io = 0;
	for(auto p : v){
		if(p.second.first) sgn += io * p.second.second;
		else io ^= 1;
	}
	cout << (sgn == 0 ? "NO" : "YES");
}


#include<bits/stdc++.h>
using namespace std;
using LD = double;
constexpr int maxn = 240000;
constexpr LD eps = 1e-10;
int sgn(LD x){
	if(x <= -eps) return -1;
	if(x >= eps) return 1;
	return 0;
}
struct P{
	LD x, y, z;
	P(LD x = 0, LD y = 0, LD z = 0): x(x), y(y), z(z){};
}p[2][maxn], pp[maxn];
LD operator * (P A, P B){return A.x * B.x + A.y * B.y + A.z * B.z;}
P operator + (P A, P B){return P(A.x + B.x, A.y + B.y, A.z + B.z);}
P operator - (P A, P B){return P(A.x - B.x, A.y - B.y, A.z - B.z);}
P operator * (P A, LD k){return P(A.x * k, A.y * k, A.z * k);}
P cross(P A, P B){return P(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);}
struct node{
	LD p;
	int b, d;
	bool operator < (const node& B){
		return p < B.p;
	}
};
int n[2], ppn, b[maxn], d[maxn];
int main(){
	ios::sync_with_stdio(false);
	cout << fixed;
	for(int t = 0; t < 2; t += 1){
		cin >> n[t];
		for(int i = 0; i < n[t]; i += 1){
			cin >> p[t][i].x >> p[t][i].y >> p[t][i].z;
			p[t][i + n[t]] = p[t][i];
		}
	}
	P na = cross(p[0][1] - p[0][0], p[0][2] - p[0][0]);
	P nb = cross(p[1][1] - p[1][0], p[1][2] - p[1][0]);
	P x = cross(na, nb);
	if(sgn(x * x) == 0){
		cout << "NO";
		return 0;
	}
	for(int t = 0; t < 2; t += 1){
		P nn = cross(p[t ^ 1][1] - p[t ^ 1][0], p[t ^ 1][2] - p[t ^ 1][0]);
		for(int i = 0; i < n[t]; i += 1){
			LD mA = nn * (p[t][i] - p[t ^ 1][0]);
			if(sgn(mA) == 0) continue;
			LD mB = nn * (p[t][i + 1] - p[t ^ 1][0]);
			if(sgn(mB) == sgn(mA)) continue;
			if(sgn(mB)){
				LD k = mA / (nn * (p[t][i] - p[t][i + 1]));
				pp[ppn] = p[t][i] + (p[t][i + 1] - p[t][i]) * k;
				b[ppn] = t;
				d[ppn] = sgn(mA);
				ppn += 1;
				continue;
			}
			LD mC = nn * (p[t][i + 2] - p[t ^ 1][0]);
			if(sgn(mC)){
				if(sgn(mA) != sgn(mC)){
					pp[ppn] = p[t][i + 1];
					b[ppn] = t;
					d[ppn] = sgn(mA);
					ppn += 1;
				}
				continue;
			}
			LD mD = nn * (p[t][i + 3] - p[t ^ 1][0]);
			if(sgn(mA) != sgn(mD)){
				pp[ppn] = p[t][i + 1];
				b[ppn] = t;
				d[ppn] = sgn(mA);
				ppn += 1;
			}
		}
	}
	if(not ppn){
		cout << "NO";
		return 0;
	}
	vector<node> v;
	for(int i = 0; i < ppn; i += 1)
		v.push_back((node){(pp[i] - pp[0]) * (pp[1] - pp[0]), b[i], d[i]});
	sort(v.begin(), v.end());
	int sgn = 0, io = 0;
	for(node A : v){
		if(A.b == 0) sgn += io * A.d;
		else io ^= 1;
	}
	cout << (sgn == 0 ? "NO" : "YES");
}


#include<bits/stdc++.h>
using namespace std;
using LD = long double;
constexpr int maxn = 120000;
constexpr LD eps = 1e-10;
int sgn(LD x){
	if(x <= -eps) return -1;
	if(x >= eps) return 1;
	return 0;
}
struct P{
	LD x, y, z;
	P(LD x = 0, LD y = 0, LD z = 0): x(x), y(y), z(z){};
}p[2][maxn], n[2];
LD operator * (P A, P B){return A.x * B.x + A.y * B.y + A.z * B.z;}
P operator + (P A, P B){return P(A.x + B.x, A.y + B.y, A.z + B.z);}
P operator - (P A, P B){return P(A.x - B.x, A.y - B.y, A.z - B.z);}
P operator * (P A, LD k){return P(A.x * k, A.y * k, A.z * k);}
P cross(P A, P B){return P(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);}
int m[2], mix[maxn];
int main(){
	ios::sync_with_stdio(false);
	for(int t = 0; t < 2; t += 1){
		cin >> m[t];
		for(int i = 0; i < m[t]; i += 1) cin >> p[t][i].x >> p[t][i].y >> p[t][i].z;
		p[t][m[t]] = p[t][0];
		n[t] = cross(p[t][1] - p[t][0], p[t][2] - p[t][0]);
	}
	if(sgn(cross(n[0], n[1]) * cross(n[0], n[1])) == 0){
		cout << "NO";
		return 0;
	}
	P X = cross(n[0], n[1]);
	vector<pair<double, pair<int, int>>> v;
	for(int t = 0; t < 2; t += 1){
		for(int i = 0; i <= m[t]; i += 1) mix[i] = sgn(p[t][i] * n[t ^ 1]);
		for(int i = 0; i < m[t]; i += 1){
			if(mix[i] == mix[i + 1]) continue;
			LD k = (n[t ^ 1] * (p[t][i] - p[t ^ 1][0])) / (n[t ^ 1] * (p[t][i] - p[t][i + 1]));
			v.push_back(make_pair(X * (p[t][i] + k * (p[t][i + 1] - p[t][i])),
				make_pair(t, mix[i] - mix[i + 1])));
		}
	}
	sort(v.begin(), v.end());
	int sgn = 0, io = 0;
	for(auto p : v){
		//cout << p.first << " " << p.second.first << " " << p.second.second << "\n";
		if(p.second.first) sgn += io * p.second.second;
		else io ^= 1;
	}
	cout << (sgn == 0 ? "NO" : "YES");
}


#include<bits/stdc++.h>
using namespace std;
using LD = long double;
constexpr int maxn = 120000;
constexpr LD eps = 1e-10;
int sgn(LD x){
	if(x <= -eps) return -1;
	if(x >= eps) return 1;
	return 0;
}
struct P{
	LD x, y, z;
	P(LD x = 0, LD y = 0, LD z = 0): x(x), y(y), z(z){};
}p[2][maxn];
LD operator * (P A, P B){return A.x * B.x + A.y * B.y + A.z * B.z;}
P operator + (P A, P B){return P(A.x + B.x, A.y + B.y, A.z + B.z);}
P operator - (P A, P B){return P(A.x - B.x, A.y - B.y, A.z - B.z);}
P operator * (P A, LD k){return P(A.x * k, A.y * k, A.z * k);}
P cross(P A, P B){return P(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);}
bool operator < (P A, P B){
	if(sgn(A.x - B.x)) return A.x < B.x;
	if(sgn(A.y - B.y)) return A.y < B.y;
	return A.z < B.z;
}
struct PP : P{
	int b, d;
	PP(P A = P(0, 0, 0), int b = 0, int d = 0): P(A), b(b), d(d){};
};
int main(){
	ios::sync_with_stdio(false);
	int n[2];
	for(int t = 0; t < 2; t += 1){
		cin >> n[t];
		for(int i = 0; i < n[t]; i += 1){
			cin >> p[t][i].x >> p[t][i].y >> p[t][i].z;
			p[t][i + n[t]] = p[t][i];
		}
	}
	vector<PP> v;
	for(int t = 0; t < 2; t += 1){
		P nn = cross(p[t ^ 1][1] - p[t ^ 1][0], p[t ^ 1][2] - p[t ^ 1][0]);
		for(int i = 0; i < n[t]; i += 1){
			LD mA = nn * (p[t][i] - p[t ^ 1][0]);
			if(sgn(mA) == 0) continue;
			LD mB = nn * (p[t][i + 1] - p[t ^ 1][0]);
			if(sgn(mB) == sgn(mA)) continue;
			if(sgn(mB)){
				LD k = mA / (nn * (p[t][i] - p[t][i + 1]));
				v.push_back(PP(p[t][i] + k * (p[t][i + 1] - p[t][i]), t, sgn(mA)));
				continue;
			}
			LD mC = nn * (p[t][i + 2] - p[t ^ 1][0]);
			if(sgn(mC)){
				if(sgn(mA) != sgn(mC)) v.push_back(PP(p[t][i + 1], t, sgn(mA)));
				continue;
			}
			LD mD = nn * (p[t][i + 3] - p[t ^ 1][0]);
			if(sgn(mA) != sgn(mD)) v.push_back(PP(p[t][i + 1], t, sgn(mA)));
		}
	}
	sort(v.begin(), v.end());
	int sgn = 0, io = 0;
	for(PP A : v){
		if(A.b == 0) sgn += io * A.d;
		else io ^= 1;
	}
	cout << (sgn == 0 ? "NO" : "YES");
}


#include<iostream>
#include<vector>

using namespace std;

vector<int> aut(1, -1);
string pattern;
vector<string> edges;
vector<vector<int>> adj;

int main() {
  int N;
  cin >> N;

  edges.resize(N + 1);
  adj.resize(N + 1);

  for(int n = 2; n <= N; ++n)
    {
      int p;
      cin >> p >> edges[n];
      adj[p].push_back(n);
    }

  cin >> pattern;

  for(int pos = 0; pos < int(pattern.size()); pos++)
    {
      int back = aut[pos];
      while(back != -1 && pattern[back] != pattern[pos])
        back = aut[back];
      aut.push_back(back+1);
    }

  vector<pair<int, int>> stack(1, make_pair(1, 0));
  int res = 0;
  while(!stack.empty())
    {
      int pos_ini = stack.back().second;
      const int node = stack.back().first;
      stack.pop_back();

      for(int next : adj[node])
        {
          int pos = pos_ini;
          for(char c : edges[next])
            {
              while(pos != -1 && c != pattern[pos])
                pos = aut[pos];
              ++pos;
              if(pos == int(pattern.size()))
                {
                  ++res;
                  pos = aut[pos];
                }
            }
          stack.push_back(make_pair(next, pos));
        }
    }

  cout << res << endl;
}


/* In the name of Allah */
#include <bits/stdc++.h>

using namespace std;

#define sz(x) (((int) x.size()))
typedef long long ll;

const int maxN = 3000*100 + 10 ;
int nex[maxN];

vector<pair<int,string>> c[maxN];
string t;
ll ans;

void dfs( int s , int curr = 0 ) {
	for( auto x : c[s] ) {
		int tmp = curr;
		string s = x.second;
		for( int i = 0 ; i < sz(s) ; i++ ) {
			while( tmp && t[tmp] != s[i] )
				tmp = nex[tmp];
			if( t[tmp] == s[i] ) tmp++;
			if( tmp == sz(t) - 1 )
				ans++;
		}
		dfs( x.first , tmp );
	}
}

int main() {
	int n;
	cin >> n;
	for( int i = 1 ; i < n ; i++ ) {
		int p; string s;
		cin >> p >> s; p--;
		c[p].emplace_back(i,s);
	}

	cin >> t;

	for( int i = 1 ; i < sz(t) ; i++ ) {
		int x = nex[i];
		while( x && t[x] != t[i] )
			x = nex[x];
		if( t[x]==t[i] ) x++;
		nex[i+1] = x;
	}
	t += 'A';

	dfs(0);

	cout << ans << endl;
}


#include <functional>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <cassert>
#include <bitset>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const int INF = 1000 * 1000 * 1000;
const int MAX_N = 100100;

#define REP(i, n) for (int i = 0; i < (n); ++i)
#define ALL(v) v.begin(), v.end()
#define SZ(v) (int) v.size()
#define MP make_pair
#define PB push_back

#define TASK ""

vector<vector<int> > g;

string st[MAX_N];
int p[MAX_N << 2];

int pt;

int ans;

string c;

void dfs(int v = 0) {
	for (int to : g[v]) {
		REP(i, SZ(st[to])) {
			int j = p[pt + i - 1];
			while (j > 0 && st[to][i] != c[j]) {
				j = p[j - 1];
			}
			if (st[to][i] == c[j]) {
				++j;
			}
			p[pt + i] = j;
			if (j == SZ(c) - 1) {
				++ans;
			}
		}
		pt += SZ(st[to]);
		dfs(to);
		pt -= SZ(st[to]);
	}
}

int main() {
	#ifdef EDDY
		freopen("input.txt", "r", stdin);
		freopen("output.txt", "w", stdout);
	#else
	//	freopen(TASK ".in", "r", stdin);
	//	freopen(TASK ".out", "w", stdout);
	#endif

	int N;

	scanf("%d", &N);

	g.resize(N);

	REP(i, N - 1) {
		int p;
		string s;
		cin >> p >> s;
		st[i + 1] = s;
		g[p - 1].PB(i + 1);
	}

	cin >> c;

	c += "#";

	for (int i = 1; i < SZ(c); ++i) {
		int j = p[i - 1];
		while (j > 0 && c[i] != c[j]) {
			j = p[j - 1];
		}
		if (c[i] == c[j]) {
			++j;
		}
		p[i] = j;
	}

	pt = SZ(c);

	dfs();

	cout << ans;

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

vector<pair<int, string>> g[100000];

#define ll long long
#define MAXN 100010
string P;
int zfn[MAXN], n, m;

/* P , pattern preprocess */
void kmpPreprocess() {
    int i=0, j=-1;
    zfn[0]=-1;
    while(i<m){
        while(j>=0 && P[i]!=P[j]) j=zfn[j];
        i++; j++;
        zfn[i]=j;
    }
}

//void kmp(){
//    occ=0;
//    int i=0, j=0;
//    while(i<n) {
//        while(j>=0 && T[i]!=P[j]) j=zfn[j];
//        i++; j++;
//        if(j==m) {
//            occI[occ++]=i-j;
//            j=zfn[j];
//        }
//    }
//}

ll kmp(int p, int e, int j){
  ll occ=0;
  int i=0;
  string s = g[p][e].second;
  int v = g[p][e].first;
  int l = s.length();
  while(i<l) {
    while(j>=0 && s[i]!=P[j]) j=zfn[j];
    i++; j++;
    if(j==m) {
      occ++;
      j=zfn[j];
    }
  }
  for (int x=0; x<g[v].size(); x++) {
    occ += kmp(v, x, j);
  }
  return occ;
}

int main() {
  cin.sync_with_stdio(false);
  cin >> n;
  for (int i=0; i<n; i++) {
    g[i] = vector<pair<int,string>>();
  }
  for (int i=1; i<n; i++) {
    int a;
    string s;
    cin >> a >> s;
    g[a-1].push_back(make_pair(i, s));
  }
  cin >> P;
  m = P.length();
  kmpPreprocess();
  ll occ = 0;
  for (int x=0; x<g[0].size(); x++) {
    occ += kmp(0, x, 0);
  }
  cout << occ << endl;
}


// .... .... .... !

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cassert>

#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>

#include <cstdio>
#include <cstring>

using namespace std;

#define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++)
#define fer(i, x, n) for (int i = (int)(x), _n = (int)(n); i < _n; i++)
#define rof(i, n, x) for (int i = (int)(n), _x = (int)(x); i-- > _x; )
#define fch(i, x) for (__typeof(x.begin()) i = x.begin(); i != x.end(); i++)
#define sz(x) (int((x).size()))
#define X first
#define Y second
#define pb push_back
#define mp make_pair
#define all(X) (X).begin(),(X).end()

typedef long long ll;
typedef pair <int, int> pii;

////////////////////////////////////////////////////////////////////////////////

const int maxn = 100000 + 100;

int n;
int p[maxn];
vector <int> ch[maxn];
string s[maxn];
string t;
int f[3*maxn];
int fs[maxn][27]; // a..z + #
int ans;

void dfs (int v)
{
	int k;
	if (v)	k = fs[p[v]][s[v][0] - 'a'];
	else	k = (t[0] == s[0][0] ? 1 : 0);

	if (k == sz(t)) ans++, k = f[k - 1];

	for (int i = 1; i < sz(s[v]); i++)
	{
		while (k > 0 && t[k] != s[v][i]) k = f[k - 1];
		if (s[v][i] == t[k]) k++;
		if (k == sz(t)) ans++, k = f[k - 1];
	}

	bool e[26];
	fill (e, e+26, false);
	for (auto c : ch[v]) e[(int)s[c][0]] = true;

	rep (i, 26)
	{
		int &kk = fs[v][i] = k;
		while (kk > 0 && t[kk] != char(i+'a')) kk = f[kk - 1];
		if (char(i+'a') == t[kk]) kk++;
	}

	for (auto c : ch[v]) dfs (c);
}

int main()
{
	ios::sync_with_stdio (false);

	cin >> n;
	fer (i, 1, n) cin >> p[i] >> s[i], p[i]--, ch[p[i]].pb (i);
	cin >> t;

	f[0] = 0;
	for (int i = 1, k = 0; i < sz(t); i++)
	{
		while (k > 0 && t[k] != t[i]) k = f[k - 1];
		if (t[i] == t[k]) k++;
		f[i] = k;
	}

	dfs (0);

	cout << ans << endl;

	{ int _; cin >> _; return 0; }
}


// .... .... .... !

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cassert>

#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>

#include <cstdio>
#include <cstring>

using namespace std;

#define rep(i, n) for (int i = 0, _n = (int)(n); i < _n; i++)
#define fer(i, x, n) for (int i = (int)(x), _n = (int)(n); i < _n; i++)
#define rof(i, n, x) for (int i = (int)(n), _x = (int)(x); i-- > _x; )
#define fch(i, x) for (__typeof(x.begin()) i = x.begin(); i != x.end(); i++)
#define sz(x) (int((x).size()))
#define X first
#define Y second
#define pb push_back
#define mp make_pair
#define all(X) (X).begin(),(X).end()

typedef long long ll;
typedef pair <int, int> pii;

////////////////////////////////////////////////////////////////////////////////

const int maxn = 100000 + 100;

int n;
int p[maxn];
vector <int> ch[maxn];
string s[maxn];
string t;
int f[3*maxn];
int fp[maxn];
int fs[3*maxn][26];
int ans;

bool e[26];

void dfs (int v)
{
	int k = (v ? fp[p[v]] : 0);

	for (int i = 0; i < sz(s[v]); i++)
	{
		k = fs[k][s[v][i]-'a'];
		if (k == sz(t)) ans++, k = f[k - 1];
	}
	fp[v] = k;

	for (auto c : ch[v]) dfs (c);
}

int main()
{
	ios::sync_with_stdio (false);

	cin >> n;
	fer (i, 1, n) cin >> p[i] >> s[i], p[i]--, ch[p[i]].pb (i);
	cin >> t;

	f[0] = 0;
	for (int i = 1, k = 0; i < sz(t); i++)
	{
		while (k > 0 && t[k] != t[i]) k = f[k - 1];
		if (t[i] == t[k]) k++;
		f[i] = k;
	}
	rep (k, sz(t))
		rep (c, 26)
			if (k > 0 && t[k] != char(c+'a')) fs[k][c] = fs[f[k-1]][c];
			else if (char(c+'a') == t[k]) fs[k][c] = k+1;

	dfs (0);

	cout << ans << endl;

	{ int _; cin >> _; return 0; }
}


#include <cstdio>
#include <cstring>
#include <cassert>
#include <vector>
#include <cstdlib>

#define pb push_back
#define sz(c) (int)(c).size()
using namespace std;

const int maxL = 1 << 20;
const int maxN = (int)1e5 + 123;
int pref[maxL];
char str[maxL];
char S[maxL];
int in[maxN][2];
int tlen;
vector<int> g[maxN];
int res;

void dfs(int s, int len) {
	int nlen;
	for (int i = 0; i < sz(g[s]); i++) {
		int u = g[s][i];
		nlen = len;
		for (int j = in[u][0]; j < in[u][1]; j++, nlen++) {
			str[nlen] = S[j];
			int k = pref[nlen - 1];
			while (k >= 0 && str[k + 1] != str[nlen]) k = pref[k];
			if (str[k + 1] == str[nlen]) k++;
			pref[nlen] = k;
			if (pref[nlen] == tlen - 1) {
				res++;
			}
		}
		dfs(u, nlen);
	}
}
int main() {
	while (1) {
		memset(S, 0, sizeof S);
		int n; scanf("%d", &n);
		if (n == 0) break;
		in[1][0] = in[1][1] = 0;
		for (int i = 0; i <= n; i++) g[i].clear();
		for (int i = 2; i <= n; i++) {
			int x; scanf("%d", &x);
			g[x].pb(i);
			in[i][0] = in[i][1] = in[i - 1][1];
			scanf("%s", S + in[i - 1][1]);
			while (S[in[i][1]]) in[i][1]++;
		}
		scanf("%s", str);
		int l = strlen(str);
		tlen = l;
		str[l++] = '#';
		pref[0] = -1;
		for (int i = 1; i < l; i++) {
			int k = pref[i - 1];
			while (k >= 0 && str[k + 1] != str[i]) k = pref[k];
			if (str[k + 1] == str[i]) k++;
			pref[i] = k;
		}
		res = 0;
		dfs(1, l);
		printf("%d\n", res);
		break;
	}
	return 0;
}


#include <algorithm>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <climits>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <deque>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <stack>
#include <list>
#include <bitset>
#include <cassert>
#define clr(x) memset((x), 0, sizeof(x))
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define mp make_pair
#define For(i, st, en) for(int i=(st); i<=(int)(en); i++)
#define Ford(i, st, en) for(int i=(st); i>=(int)(en); i--)
#define forn(i, n) for(int i=0; i<(int)(n); i++)
#define ford(i, n) for(int i=(n)-1; i>=0; i--)
#define fori(it, x) for (__typeof((x).begin()) it = (x).begin(); it != (x).end(); it++)
#define in(x) int (x); input((x));
#define x first
#define y second
#define less(a,b) ((a) < (b) - EPS)
#define more(a,b) ((a) > (b) + EPS)
#define eq(a,b) (fabs((a) - (b)) < EPS)
#define remax(a, b) ((a) = (b) > (a) ? (b) : (a))
#define remin(a, b) ((a) = (b) < (a) ? (b) : (a))
int clock0 = clock();
using namespace std; typedef long double ld; template <class _T> inline _T sqr(const _T& x) {return x * x;} template <class _T> inline string tostr(const _T& a) {ostringstream os(""); os << a; return os.str();} const ld PI = 3.1415926535897932384626433832795L; const ld EPS = 4e-5; char TEMPORARY_CHAR; typedef long long ll; typedef unsigned long long ull; typedef set < int > SI; typedef vector < int > VI; typedef vector < vector < int > > VVI; typedef map < string, int > MSI; typedef pair < int, int > PII; const int INF = 2e9; typedef complex<ld> cbase; inline void fft (vector<cbase> &a, bool invert) {int n = (int)a.size(); for (int i = 1, j = 0; i < n; ++i) {int bit = n >> 1; for (; j >= bit; bit >>= 1) j -= bit; j += bit; if (i < j) swap(a[i], a[j]);} for (int len = 2; len <= n; len <<= 1) {ld ang = 2 * PI / len * (invert ? -1 : 1); cbase wlen(cos(ang), sin(ang)); for (int i = 0; i < n; i += len) {cbase w(1); for (int j=0; j < len / 2; ++j) {cbase u = a[i + j], v = a[i + j + len / 2] * w; a[i + j] = u + v; a[i + j + len / 2] = u - v; w *= wlen;}}} if (invert) for (int i = 0; i < n; ++i) a[i] /= n;} inline void input(int &a) {a = 0; while (((TEMPORARY_CHAR = getchar()) > '9' || TEMPORARY_CHAR < '0') && (TEMPORARY_CHAR != '-')){} char neg = 0; if (TEMPORARY_CHAR == '-') {neg = 1; TEMPORARY_CHAR = getchar();} while (TEMPORARY_CHAR <= '9' && TEMPORARY_CHAR >= '0') {a = (a << 3) + (a << 1) + TEMPORARY_CHAR - '0'; TEMPORARY_CHAR = getchar();} if (neg) a = -a;} inline void out(int a) {if (!a) putchar('0'); if (a < 0) {putchar('-'); a = -a;} char s[10]; int i; for(i = 0; a; ++i) {s[i] = '0' + a % 10; a /= 10;} ford(j, i) putchar(s[j]);} inline int nxt() {in(ret); return ret;} struct lnum {vector <int> a; int base; lnum(int num = 0, int base = 1000000000):base(base) {if (!num) a.resize(1); while(num) {a.pb(num % base); num /= base;}} inline int len() const {return a.size();} lnum & operator=(const lnum &l) {if (this != &l) {a = l.a; base = l.base;} return *this;} inline friend lnum operator+(const lnum &l, const lnum &r) {lnum ret(0, l.base); int base = l.base; int ln = l.len(), rn = r.len(); int n = max(ln, rn); ret.a.resize(n); int o = 0; for(int i = 0; i < n; ++i) {int s = o; if (i < ln) s += l.a[i]; if (i < rn) s += r.a[i]; o = s >= base; if (o) s -= base; ret.a[i] = s;} if (o) ret.a.push_back(1); return ret;} inline friend lnum operator-(const lnum &l, const lnum &r) {lnum ret(0, l.base); int base = l.base; int n = l.len(); int rn = r.len(); ret.a.resize(n); int o = 0; for(int i = 0; i < n; ++i) {int s = l.a[i] - o; if (i < rn) s -= r.a[i]; o = s < 0; if (o) s += base; ret.a[i] = s;} if (ret.len() > 1 && !ret.a.back()) ret.a.pop_back(); return ret;} inline friend lnum operator*(const lnum &l, const lnum &r) {lnum ret(0, l.base); int base = l.base; if (l.len() * r.len() > 1000000) {vector<cbase> fa (l.a.begin(), l.a.end()), fb (r.a.begin(), r.a.end()); int n = 1; while (n < max (l.len(), r.len())) n <<= 1; n <<= 1; fa.resize (n), fb.resize (n); fft (fa, false), fft (fb, false); for (int i = 0; i < n; ++i) fa[i] *= fb[i]; fft (fa, true); ret.a.resize(n); for (int i = 0; i < n; ++i) ret.a[i] = int (fa[i].real() + 0.5); int carry = 0; for (int i=0; i < n; ++i) {ret.a[i] += carry; carry = ret.a[i] / base; ret.a[i] %= base;}} else {ret.a.resize(l.len() + r.len()); for (int i = 0; i < l.len(); ++i) for (int j = 0, carry = 0; j < r.len() || carry; ++j) {long long cur = ret.a[i + j] + (ll)l.a[i] * (j < r.len() ? r.a[j] : 0) + carry; ret.a[i + j] = cur % base; carry = cur / base;}} while (ret.len() > 1 && !ret.a.back()) ret.a.pop_back(); return ret;} inline friend lnum operator/(const lnum &l, const int &r) {lnum ret(0, l.base); ret.a.resize(l.len()); int carry = 0; for(int i = l.len() - 1; i >= 0; --i) {long long cur = l.a[i] + (ll)carry * l.base; ret.a[i] = cur / r; carry = cur % r;} while (ret.len() > 1 && ret.a.back() == 0) ret.a.pop_back(); return ret;}  inline friend bool operator<(const lnum &l, const lnum &r) {if (l.len() < r.len()) return true; if (l.len() > r.len()) return false; int n = l.len(); for(int i = n - 1; i >= 0; --i) {if (l.a[i] < r.a[i]) return true; if (l.a[i] > r.a[i]) return false;} return false;} inline friend bool operator>(const lnum &l, const lnum &r) {return r < l;} inline friend bool operator==(const lnum &l, const lnum &r) {if (l.len() != r.len()) return false; int n = l.len(); for(int i = n - 1; i; --i) {if (l.a[i] != r.a[i]) return false;} return true;} inline friend bool operator!=(const lnum &l, const lnum &r) {return !(l == r);} inline void print() {if (base == 1000000000) {printf("%d", a.back()); for(int i = a.size() - 2; i >=0; --i) printf("%09d", a[i]);} else {for(int i = a.size() - 1; i >= 0; --i) printf("%d", a[i]);}}};

int ans = 0;
int l;
vector <int> pr;
vector <vector <pair <int, string> > > g;
string t;

void dfs(int v, int state)
{
    forn(i, g[v].size())
    {
        int to = g[v][i].x;
        int s = state;
        forn(j, g[v][i].y.length())
        {
            int k = s;
            while(k && g[v][i].y[j] != t[k])
                k = pr[k - 1];
            if (g[v][i].y[j] == t[k]) ++k;
            s = k;
            if (s == l - 1)
                ++ans;
        }
        dfs(to, s);
    }
}

int main()
{
    in(n);
    g.resize(n);
    forn(i, n - 1)
    {
        int p;
        string s;
        cin >> p >> s;
        --p;
        g[p].pb(mp(i + 1, s));
    }
    cin >> t;
    t += "#";
    l = t.length();
    pr.resize(l);
    For(i, 1, l - 1)
    {
        int j = pr[i - 1];
        while(j && t[i] != t[j])
            j = pr[j - 1];
        if (t[i] == t[j]) ++j;
        pr[i] = j;
    }
    dfs(0, 0);
    cout << ans << endl;

    return 0;
}


//link: http://codeforces.com/problemset/problem/291/E
#include <cstdlib>
#include <cstdio>
//#include <bits/stdc++.h>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <cstring>
#include <climits>
#include <cmath>
#include <ctime>
#include <cfloat>
#include <cassert>
#include <algorithm>
#include <utility>
#include <numeric>
#include <functional>

#include <queue>
#include <deque>
#include <vector>
#include <list>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <bitset>

/*
#include <unordered_map>
#include <unordered_set>
*/

#define llint long long
#define vi vector<int>
#define ii pair<int, int>
#define iii pair<int, ii>
#define iiii pair<ii,ii>
#define vii vector<ii>
const long double eps=1e-9;

#define pb push_back
#define mp make_pair
#define sz( a ) ( (int) a.size() )
using namespace std;

#if 0
#define what_is( _X ) cerr << #_X << " is " << _X << endl;
#define gcd( _a, _b ) __gcd( _a, _b )
inline int sum(){ return 0; }
template < typename... Args >
int sum( int _a, Args... _args ){return _a + sum( _args... );}
#endif

template < class T >inline T MAX (const T &_a, const T &_b){return ((_a>_b)?_a:_b);}
template < class T >inline T MIN (const T &_a, const T &_b){return ((_a<_b)?_a:_b);}
template < class T >inline T MAX3(const T &_a, const T &_b, const T &_c){return MAX(MAX(_a,_b),_c);}
template < class T >inline T MIN3(const T &_a, const T &_b, const T &_c){return MIN(MIN(_a,_b),_c);}
template < class T >inline T MAX4(const T &_a, const T &_b, const T &_c, const T &_d){return MAX(MAX3(_a,_b,_c),_d);}
template < class T >inline T MIN4(const T &_a, const T &_b, const T &_c, const T &_d){return MIN(MIN3(_a,_b,_c),_d);}
template < class T >inline T ABS (const T &_a){return ((_a<0)?-_a:_a);}
template < class T >inline T SQR (const T &_a){return _a*_a;}
template < class T >inline T gcd(T _a,T _b){for(T _r;(_r=_a%_b);_b=_r)_a=_b;return _b;}
template < class T >inline T lcm(const T &_a,const T &_b){return (_a/gcd(_a,_b))*_b;}
template < class T >inline bool BETW(const T&_a,const T&_b,const T&_c){return (_a>=MIN(_b,_c)&&_a<=MAX(_b,_c));}
template < class T >inline bool EXT (const T&_a,const T&_b,const T&_c){return !BETW(_a,_b,_c);}

const int MAXN = 100010, MAXS = 300010;
int N, b[MAXS];
vector<int> adj[MAXN];
string S[MAXN], ss;
long long ans;

inline void KMP_preprocess(){
    int i = 0, j = b[0] = -1;
    while( i < sz(ss) ){
        while( j >= 0 && ss[i] != ss[j] )j = b[j];
        ++i; ++j;
        b[i] = j;
    }
}

inline int KMP_match( string &T, int j ){
    int i = 0;
    while( i < sz(T) ){
        while( j >= 0 && T[i] != ss[j] )j = b[j];
        i++; j++;
        if( j == sz(ss) )ans++;
    }
    return j;
}

void dfs( int node, int state ){
    for( int i = 0; i < sz(adj[node]); ++i )
        dfs( adj[node][i], KMP_match( S[adj[node][i]], state ) );
}

int main(){
    int i, f;
    ios::sync_with_stdio(false);
    cin >> N;
    for( i = 2; i <= N; ++i ){
        cin >> f >> S[i];
        adj[f].push_back(i);
    } cin >> ss;
    KMP_preprocess();
    dfs( 1, 0 );
    cout << ans;
    return 0;
}


//link: http://codeforces.com/problemset/problem/291/E
#include <cstdlib>
#include <cstdio>
//#include <bits/stdc++.h>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <cstring>
#include <climits>
#include <cmath>
#include <ctime>
#include <cfloat>
#include <cassert>
#include <algorithm>
#include <utility>
#include <numeric>
#include <functional>

#include <queue>
#include <deque>
#include <vector>
#include <list>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <bitset>

/*
#include <unordered_map>
#include <unordered_set>
*/

#define llint long long
#define vi vector<int>
#define ii pair<int, int>
#define iii pair<int, ii>
#define iiii pair<ii,ii>
#define vii vector<ii>
const long double eps=1e-9;

#define pb push_back
#define mp make_pair
#define sz( a ) ( (int) a.size() )
using namespace std;

#if 0
#define what_is( _X ) cerr << #_X << " is " << _X << endl;
#define gcd( _a, _b ) __gcd( _a, _b )
inline int sum(){ return 0; }
template < typename... Args >
int sum( int _a, Args... _args ){return _a + sum( _args... );}
#endif

template < class T >inline T MAX (const T &_a, const T &_b){return ((_a>_b)?_a:_b);}
template < class T >inline T MIN (const T &_a, const T &_b){return ((_a<_b)?_a:_b);}
template < class T >inline T MAX3(const T &_a, const T &_b, const T &_c){return MAX(MAX(_a,_b),_c);}
template < class T >inline T MIN3(const T &_a, const T &_b, const T &_c){return MIN(MIN(_a,_b),_c);}
template < class T >inline T MAX4(const T &_a, const T &_b, const T &_c, const T &_d){return MAX(MAX3(_a,_b,_c),_d);}
template < class T >inline T MIN4(const T &_a, const T &_b, const T &_c, const T &_d){return MIN(MIN3(_a,_b,_c),_d);}
template < class T >inline T ABS (const T &_a){return ((_a<0)?-_a:_a);}
template < class T >inline T SQR (const T &_a){return _a*_a;}
template < class T >inline T gcd(T _a,T _b){for(T _r;(_r=_a%_b);_b=_r)_a=_b;return _b;}
template < class T >inline T lcm(const T &_a,const T &_b){return (_a/gcd(_a,_b))*_b;}
template < class T >inline bool BETW(const T&_a,const T&_b,const T&_c){return (_a>=MIN(_b,_c)&&_a<=MAX(_b,_c));}
template < class T >inline bool EXT (const T&_a,const T&_b,const T&_c){return !BETW(_a,_b,_c);}

const int MAXN = 100010, MAXS = 300010;
int N, b[MAXS];
vector<int> adj[MAXN];
string S[MAXN], ss;
long long ans;

inline void KMP_preprocess(){
    int i = 0, j = b[0] = -1;
    while( i < sz(ss) ){
        while( j >= 0 && ss[i] != ss[j] )j = b[j];
        ++i; ++j;
        b[i] = j;
    }
}

inline int KMP_match( string &T, int j ){
    int i = 0;
    while( i < sz(T) ){
        while( j >= 0 && T[i] != ss[j] )j = b[j];
        i++; j++;
        if( j == sz(ss) )ans++, j = b[j];
    }
   // cout << T << " " << j << endl;
    return j;
}

void dfs( int node, int state ){
  //  cout << node << " " << state << endl;
    for( int i = 0; i < sz(adj[node]); ++i )
        dfs( adj[node][i], KMP_match( S[adj[node][i]], state ) );
}

int main(){
    int i, f;
    ios::sync_with_stdio(false);
    cin >> N;
    for( i = 2; i <= N; ++i ){
        cin >> f >> S[i];
        adj[f].push_back(i);
    } cin >> ss;
    KMP_preprocess();
    dfs( 1, 0 );
    cout << ans;
    return 0;
}


//link: http://codeforces.com/problemset/problem/291/E
#include <cstdlib>
#include <cstdio>
//#include <bits/stdc++.h>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <cstring>
#include <climits>
#include <cmath>
#include <ctime>
#include <cfloat>
#include <cassert>
#include <algorithm>
#include <utility>
#include <numeric>
#include <functional>

#include <queue>
#include <deque>
#include <vector>
#include <list>
#include <stack>
#include <map>
#include <set>
#include <string>
#include <bitset>

/*
#include <unordered_map>
#include <unordered_set>
*/

#define llint long long
#define vi vector<int>
#define ii pair<int, int>
#define iii pair<int, ii>
#define iiii pair<ii,ii>
#define vii vector<ii>
const long double eps=1e-9;

#define pb push_back
#define mp make_pair
#define sz( a ) ( (int) a.size() )
using namespace std;

#if 0
#define what_is( _X ) cerr << #_X << " is " << _X << endl;
#define gcd( _a, _b ) __gcd( _a, _b )
inline int sum(){ return 0; }
template < typename... Args >
int sum( int _a, Args... _args ){return _a + sum( _args... );}
#endif

template < class T >inline T MAX (const T &_a, const T &_b){return ((_a>_b)?_a:_b);}
template < class T >inline T MIN (const T &_a, const T &_b){return ((_a<_b)?_a:_b);}
template < class T >inline T MAX3(const T &_a, const T &_b, const T &_c){return MAX(MAX(_a,_b),_c);}
template < class T >inline T MIN3(const T &_a, const T &_b, const T &_c){return MIN(MIN(_a,_b),_c);}
template < class T >inline T MAX4(const T &_a, const T &_b, const T &_c, const T &_d){return MAX(MAX3(_a,_b,_c),_d);}
template < class T >inline T MIN4(const T &_a, const T &_b, const T &_c, const T &_d){return MIN(MIN3(_a,_b,_c),_d);}
template < class T >inline T ABS (const T &_a){return ((_a<0)?-_a:_a);}
template < class T >inline T SQR (const T &_a){return _a*_a;}
template < class T >inline T gcd(T _a,T _b){for(T _r;(_r=_a%_b);_b=_r)_a=_b;return _b;}
template < class T >inline T lcm(const T &_a,const T &_b){return (_a/gcd(_a,_b))*_b;}
template < class T >inline bool BETW(const T&_a,const T&_b,const T&_c){return (_a>=MIN(_b,_c)&&_a<=MAX(_b,_c));}
template < class T >inline bool EXT (const T&_a,const T&_b,const T&_c){return !BETW(_a,_b,_c);}

const int MAXN = 100010, MAXS = 300010;
int N, b[MAXS];
vector<int> adj[MAXN];
string S[MAXN], ss;
int ans;

inline void KMP_preprocess(){
    int i = 0, j = b[0] = -1;
    while( i < sz(ss) ){
        while( j >= 0 && ss[i] != ss[j] )j = b[j];
        b[++i] = ++j;
    }
}

inline int KMP_match( string &T, int j ){
    int i = 0;
    while( i < sz(T) ){
        while( j >= 0 && T[i] != ss[j] )j = b[j];
        i++; j++;
        if( j == sz(ss) )ans++, j = b[j];
    } return j;
}

void dfs( int node, int state ){
    for( int i = 0; i < sz(adj[node]); ++i )
        dfs( adj[node][i], KMP_match( S[adj[node][i]], state ) );
}

int main(){
    int i, f;
    ios::sync_with_stdio(false);
    cin >> N;
    for( i = 2; i <= N; ++i ){
        cin >> f >> S[i];
        adj[f].push_back(i);
    } cin >> ss;
    KMP_preprocess();
    dfs( 1, 0 );
    cout << ans;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define MAXN 100010
#define MAXS 300010
class KMP {
	int reset[MAXS];
	string w;
	public:
	    KMP() {}
	    void Build(const string& x) {
			w=x;
			reset[ 0 ] = -1;
			for(int i=1;i<(int)w.size();i++) {
				int j=reset[ i-1 ];
				while(j>=0 && w[j+1]!=w[i]) j=reset[j];
				if(w[j+1]==w[i]) ++j;
				reset[i]=j;
			}
		}
	    int Go(int pos, char l) {
			int j=pos;
			while(j>=0 && w[j+1]!=l) j=reset[j];
			if(w[j+1]==l) ++j;
			return j;
		}
};

struct arco {
	int verso;
	string p;
	arco() : verso(0) {}
	arco(int n, string x) : verso(n), p(x) {}
};
int N;
vector< arco > colleg[MAXN];
string pattern;
char buf[MAXS];
KMP Macchina;
long long ris;

void Dfs(int n, int stato) {
	for(auto i: colleg[n]) {
	    int j=stato;
	    for(auto k : i.p) {
			j= Macchina.Go(j,k);
			if(j==(int)pattern.size()-1) ++ris;
		}
	    Dfs(i.verso,j);
    }
}
int main() {
	scanf("%d",&N);
	int a;
	string appo;
	for(int i=1;i<N;i++) {
		scanf("%d %s",&a,buf);
		appo=buf;
		colleg[a].emplace_back( arco(i+1, appo) );
	}
	scanf("%s",buf);
	pattern=buf;
	Macchina.Build(pattern);
	Dfs(1,-1);
	printf("%lld\n",ris);
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

#define MAXN 300010

class KMP {
	int reset[MAXN];
	string w;
	public:
	    KMP() {}
	    void Build(const string& x) {
			w=x;
			reset[ 0 ] = -1;
			for(int i=1;i<(int)w.size();i++) {
				int j=reset[ i-1 ];
				while(j>=0 && w[j+1]!=w[i]) j=reset[j];
				if(w[j+1]==w[i]) ++j;
				reset[i]=j;
			}
		}
	    int Go(int pos, char l) {
			int j=pos;
			while(j>=0 && w[j+1]!=l) j=reset[j];
			if(w[j+1]==l) ++j;
			return j;
		}
};

struct arco {
	int verso;
	string p;
	arco() : verso(0) {}
	arco(int n, string x) : verso(n), p(x) {}
};
int N;
vector< arco > colleg[MAXN];
string pattern;
char buf[MAXN];
KMP Macchina;
long long ris;

void Dfs(int n, int stato) {
	//cout<<"Sono in nodo "<<n<<" con stato "<<stato<<endl;
	for(auto i: colleg[n]) {
	    int j=stato;
	    //cout<<" Arco da "<<n<<" in "<<j<<" con verso "<<i.verso<<endl;
	    for(auto k : i.p) {
			//cout<<"   Carattere "<<k<<endl;
			j= Macchina.Go(j,k);
			//cout<<"   J: "<<j<<endl;
			if(j==(int)pattern.size()-1) ++ris;
		}
	    Dfs(i.verso,j);
    }
}
int main() {
	scanf("%d",&N);
	int a;
	string appo;
	for(int i=1;i<N;i++) {
		scanf("%d %s",&a,buf);
		appo=buf;
		colleg[a].emplace_back( arco(i+1, appo) );
	}
	scanf("%s",buf);
	pattern=buf;
	Macchina.Build(pattern);
	Dfs(1,-1);
	printf("%lld\n",ris);
	return 0;
}


#include <algorithm>
#include <iostream>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>

using namespace std;

void compute_prefix_function(const string& s, vector<int>& p) {
    p.resize(s.size() + 1);
    p[0] = -1;
    int q = -1;
    for (size_t i = 1; i <= s.size(); ++i) {
        while (q >= 0 && s[q] != s[i-1])
            q = p[q];
        ++q;
        p[i] = q;
    }
}

vector<vector<int> > children;
vector<vector<string> > child_edges;

string needle;
vector<int> p;
vector<int> automaton[30];

int count(int v, int cur_q) {
    int res = 0;
    //cerr << v << ": " << cur_q << endl;
    for (size_t i = 0; i < children[v].size(); ++i) {
        const string& s = child_edges[v][i];
        int q = cur_q;
        for (auto c = s.begin(); c != s.end(); ++c) {
            q = automaton[*c - 'a'][q];
            if (q == (int)needle.size()) {
                ++res;
                q = p[q];
            }
        }
        res += count(children[v][i], q);
    }
    return res;
}

int main() {
    int n;
    cin >> n;
    children.resize(n);
    child_edges.resize(n);
    for (int i = 1; i < n; ++i) {
        int p;
        string s;
        cin >> p >> s;
        --p;
        children[p].push_back(i);
        child_edges[p].push_back(s);
    }
    cin >> needle;
    compute_prefix_function(needle, p);
    for (char c = 'a'; c <= 'z'; ++c)
        automaton[c-'a'].resize(needle.size());
    for (size_t i = 0; i < needle.size(); ++i) {
        for (char c = 'a'; c <= 'z'; ++c) {
            int q = i;
            if (needle[q] == c)
                ++q;
            else if (q != 0)
                q = automaton[c-'a'][p[q]];
            automaton[c-'a'][i] = q;
        }
    }

    cout << count(0, 0) << endl;
    return 0;
}


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <string>
#include <map>

using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef unsigned int uint;

vector<int> edge[111111];
int fa[111111];
string faStr[111111];
char buf[333333];

char pattern[333333];
int k_next[333333];
int plen = 0;

int ans = 0;
int dep = 0;

int dfs(int x)
{
	int indep = dep;
	int tlen = faStr[x].length();
	for(int i = 0;i < tlen;i++)
	{
		while(dep > 0 && pattern[dep] != faStr[x][i]) dep = k_next[dep-1];
		if(pattern[dep] == faStr[x][i]) dep++;
		if(dep == plen)
		{
			ans++;
			dep = k_next[dep-1];
		}
	}

	for(auto y: edge[x])
	{
		dfs(y);
	}
	dep = indep;
	return 0;
}

int main(void)
{
	int n = 0;
	scanf("%d",&n);
	for(int i = 1;i < n;i++)
	{
		scanf("%d %s",&fa[i],buf);
		fa[i]--;
		edge[fa[i]].push_back(i);
		faStr[i] = buf;
	}
	scanf("%s",pattern);
	plen = strlen(pattern);

	int now = 0;
	for(int i = 1;i < plen;i++)
	{
		while(now && pattern[i] != pattern[now]) now = k_next[now-1];
		if(pattern[i] == pattern[now]) now++;
		k_next[i] = now;
	}

	dfs(0);
	printf("%d\n",ans);
	while(getchar() != EOF);
	return 0;
}


#include <set>
#include <map>
#include <string>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <cassert>
#include <climits>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <fstream>
#include <sstream>
#include <iostream>
#include <algorithm>

using namespace std;

#define LL long long
#define F first
#define S second
#define PB push_back
#define PF push front
#define MP make_pair
#define REP(x, n) for(int x=0; x<(n); ++x)
#define FOR(x, b, e) for(int x=b; x<=(e); ++x)
#define FORD(x, b, e) for(int x=b; x>=(e); --x)
#define VAR(v,n) __typeof(n) v=(n)
#define FOREACH(i,c) for(VAR(i,(c).begin());i!=(c).end();++i)
#define MOD(x, n) ((x)%(n)+(n))%(n)
#define SZ(x) (int((x).size()))
#define ALL(x) ((x).begin()),((x).end())
#define SORT(v) sort((v).begin(),(v).end())
#define REV(v) reverse((v).begin(),(v).end())
#define UNIQUE(v) SORT(v),(v).erase(unique((v).begin(),(v).end()),(v).end())
LL GCD( LL a , LL b ) { while( b ) b ^= a ^= b ^= a %= b ; return a ; }
LL LCM( LL a , LL b ) { return a * ( b / GCD( a , b ) ) ; }

typedef vector<int>    VI;
typedef vector<VI>     VVI;
typedef vector<LL>     VLL;
typedef vector<bool>   VB;
typedef vector<double> VD;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef vector<PII>    VPII;
typedef pair<LL, LL>   PLL;
typedef vector<PLL>    VPLL;

const double EPS = 10e-9;
const LL INF = (1LL << 30);

using namespace std;

struct node {
    int i;
    string str;
    vector<int> childs;
};

VI prefix(string &s) {
    VI pi(s.size()+1, 0);

    int q = 0;
    FOR(i, 1, SZ(s)-1) {
        while(q > 0 && s[q] != s[i]) {
            q = pi[q];
        }
        if(s[q] == s[i])
            q++;
        pi[i+1] = q;
    }

    return pi;
}

vector<node> nodes;
void dfs(const node &nd, const VI &pi, const string &s, int q, int &cnt) {
    REP(i, nd.str.size()) {
        while(q > 0 && s[q] != nd.str[i])
            q = pi[q];
        if(s[q] == nd.str[i])
            q++;
        if(q == s.size()) {
            cnt++;
        }
    }

    REP(j, nd.childs.size()) {
        dfs(nodes[nd.childs[j]], pi, s, q, cnt);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif

    int N;
    cin >> N;

    nodes = vector<node>(N);
    FOR(i, 1, N-1){
        int p;
        string str;
        cin >> p >> str;
        nodes[i].i = i;
        nodes[i].str = str;
        nodes[p-1].childs.push_back(i);
    }

    string s;
    cin >> s;

    int cnt = 0;
    VI pi = prefix(s);
    dfs(nodes[0], pi, s, 0, cnt);

    cout << cnt << endl;

    return 0;
}


#include <bits/stdc++.h>
#define Pb push_back
#define Mp make_pair
#define X first
#define Y second

using namespace std;

const int maxn = 1000 * 100 + 12;
int f[maxn], ans;
string t;
vector <pair <int, string> > nei[maxn];
void input(int n){

    ios::sync_with_stdio(0); cin.tie(0);
    for(int i = 1; i < n; i ++){
        int p;
        string a;
        cin >> p >> a, p --;
        nei[p].Pb(Mp(i, a));
    }
    cin >> t;
}
void seting(){

    ios::sync_with_stdio(0); cin.tie(0);
    int k = 0;
    for(int i = 1; i < t.size(); i ++){
        while(k && t[i] != t[k])
            k = f[k - 1];
        if(t[i] == t[k])
            k ++;
        f[i] = k;
       // cerr << k << endl;
    }
}
void dfs(int v = 0, int tmp = 0){
    ios::sync_with_stdio(0); cin.tie(0);
    for(auto u : nei[v]){
        int k = tmp;
        for(int j = 0; j < u.Y.size(); j ++){
            while(k && u.Y[j] != t[k])
                k = f[k - 1];
            if(u.Y[j] == t[k])
                k ++;
            if(k == t.size()){
                //cerr << " k : " << k << endl;
                //cerr << v << " " << j << endl;
                ans ++;
                k = f[k - 1];
            }
        }
        dfs(u.X, k);
    }
}
int main()
{

    ios::sync_with_stdio(0); cin.tie(0);
    int n;
    cin >> n;
    input(n);
    seting();
    dfs();
    cout << ans;
    return 0;
}


#include <bits/stdc++.h>
#define Pb push_back
#define Mp make_pair
#define X first
#define Y second

using namespace std;

const int maxn = 1000 * 100 + 12;
int f[maxn], ans;
int g[maxn][30];
string t;
vector <pair <int, string> > nei[maxn];
void input(int n){

    ios::sync_with_stdio(0); cin.tie(0);
    for(int i = 1; i < n; i ++){
        int p;
        string a;
        cin >> p >> a, p --;
        nei[p].Pb(Mp(i, a));
    }
    cin >> t;
}
void seting(){

    ios::sync_with_stdio(0); cin.tie(0);
    int k = 0;
    for(int i = 1; i < t.size(); i ++){
        while(k && t[i] != t[k])
            k = f[k - 1];
        if(t[i] == t[k])
            k ++;
        f[i] = k;
    }
    for(int i = 0; i < t.size(); i ++){
        int k = i;
        //cerr << " i : " << i << " k : " << k << " \n";
        for(int j = 0; j < 27; j ++){
            if(k == 0)
                g[i][j] = (t[k] == 'a' + j);
            else if(t[k] == 'a' + j)
                g[i][j] = k + 1;
            else
                g[i][j] = g[f[k - 1]][j];
          //  cerr << " j : " << j << " g[i][j] : " << g[i][j];
        }
    }
}
void dfs(int v = 0, int tmp = 0){
    ios::sync_with_stdio(0); cin.tie(0);
    for(auto u : nei[v]){
        int k = tmp;
        for(int j = 0; j < u.Y.size(); j ++){
            k = g[k][u.Y[j] - 'a'];
            if(k == t.size()){
                //cerr << v << " ";
                ans ++;
                k = f[k - 1];
                //cerr << k << endl;
            }
        }
        dfs(u.X, k);
    }
}
int main()
{

    ios::sync_with_stdio(0); cin.tie(0);
    int n;
    cin >> n;
    input(n);
    seting();
    dfs();
    cout << ans;
    return 0;
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count;
unsigned int ht,h,tmp=1;
unsigned int n,i,j,par[100009],len,lens[100009];
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x;
	unsigned int y;
public:
	coord(unsigned int xs){
		x=xs;
		y=lens[x]-1;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=lens[x]-1;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		j+=(lens[i]=strlen(strs[i]))+1;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		//flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			//flag=flag&&(*c2==str[i]);
		}
		count+=(!str[i]&&ht==h);
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(!(vis.insert(*(unsigned long long*)(&c1)).second)){
				break;
			}
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				/*coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);*/
				++count;
			}
			++c2;
		}
	}
	printf("%I64u\n",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count;
unsigned int ht,h,tss[300009],hsb[700000],tmp=1;
unsigned int* hss[100009];
unsigned int n,i,j,par[100009],len,lens[100009];
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x;
	unsigned int y;
public:
	coord(unsigned int xs){
		x=xs;
		y=lens[x]-1;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=lens[x]-1;
		}
	}
	unsigned int operator+=(unsigned int xs){
		unsigned int r=0;
		while(xs){
			if(xs<=y){
				y-=xs;
				r+=hss[x][y+1];
				break;
			}else{
				xs-=y+1;
				r+=hss[x][0]*tss[xs];
				x=par[x];
				if(x<2){
					return (!xs)?r:(h+1);
				}
				y=lens[x]-1;
			}
		}
		return r;
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		hss[i]=hsb+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		j+=(lens[i]=strlen(strs[i]))+1;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	tss[0]=1;
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
		tss[i+1]=tss[i]*p_num;
	}
	for(i=2;i<=n;++i){
		for(j=lens[i];j-->0;){
			hss[i][j]=hss[i][j+1]*p_num+strs[i][j];
		}
	}
	tmp=tss[len-1];
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		/*ht=0;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
		}*/
		ht=(c2+=len);
		count+=(ht==h);
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(!(vis.insert(*(unsigned long long*)(&c1)).second)){
				break;
			}
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				/*coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);*/
				++count;
			}
			++c2;
		}
	}
	printf("%I64u\n",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count,ht,h,tmp=1;
unsigned int n,i,j,par[100009],len;
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x,y;
public:
	coord(unsigned int xs){
		x=xs;
		y=0;
		while(strs[x][y]){
			++y;
		}
		--y;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=0;
			while(strs[x][y]){
				++y;
			}
			--y;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		while(buf[j]){
			++j;
		}
		++j;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			flag=flag&&(*c2==str[i]);
		}
		count+=(flag&&!str[i]);
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(vis.count(*(unsigned long long*)(&c1))){
				break;
			}
			vis.insert(*(unsigned long long*)(&c1));
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				/*coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);*/
				++count;
			}
			++c2;
		}
	}
	printf("%I64u\n",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count,ht,h,tmp=1;
unsigned int n,i,j,par[100009],len,lens[100009];
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x,y;
public:
	coord(unsigned int xs){
		x=xs;
		y=lens[x]-1;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=0;
			while(strs[x][y]){
				++y;
			}
			--y;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		j+=(lens[i]=strlen(strs[i]))+1;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			flag=flag&&(*c2==str[i]);
		}
		count+=(flag&&!str[i]);
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(vis.count(*(unsigned long long*)(&c1))){
				break;
			}
			vis.insert(*(unsigned long long*)(&c1));
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				/*coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);*/
				++count;
			}
			++c2;
		}
	}
	printf("%I64u\n",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count,ht,h,tmp=1;
unsigned int n,i,j,par[100009];
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x,y;
public:
	coord(unsigned int xs){
		x=xs;
		y=0;
		while(strs[x][y]){
			++y;
		}
		--y;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=0;
			while(strs[x][y]){
				++y;
			}
			--y;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		while(buf[j]){
			++j;
		}
		++j;
	}
	str=buf+j;
	scanf("%s",str);
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			flag=flag&&(*c2==str[i]);
		}
		count+=flag;
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(vis.count(*(unsigned long long*)(&c1))){
				break;
			}
			vis.insert(*(unsigned long long*)(&c1));
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);
			}
			++c2;
		}
	}
	printf("%I64u",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count;
unsigned int ht,h,tmp=1;
unsigned int n,i,j,par[100009],len,lens[100009];
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x;
	unsigned int y;
public:
	coord(unsigned int xs){
		x=xs;
		y=lens[x]-1;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=0;
			while(strs[x][y]){
				++y;
			}
			--y;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		j+=(lens[i]=strlen(strs[i]))+1;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		//flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			//flag=flag&&(*c2==str[i]);
		}
		count+=(!str[i]&&ht==h);
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(!(vis.insert(*(unsigned long long*)(&c1)).second)){
				break;
			}
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				/*coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);*/
				++count;
			}
			++c2;
		}
	}
	printf("%I64u\n",count);
}


#include <stdio.h>
#include <set>
#include <unordered_set>
#include <string>
#include <string.h>

#define p_num 3187

char buf[700000];
char sandbox[]="a";
char* strs[100009];
char* str;
unsigned long long count,ht,h,tmp=1;
unsigned int n,i,j,par[100009],len;
std::set<unsigned int> st;
std::set<unsigned int>::iterator it;
bool flag;
std::unordered_set<unsigned long long> vis;

class coord{
	unsigned int x,y;
public:
	coord(unsigned int xs){
		x=xs;
		y=0;
		while(strs[x][y]){
			++y;
		}
		--y;
	}
	inline char operator*(){
		return strs[x][y];
	}
	inline bool operator!(){
		return (1<x);
	}
	void operator++(){
		--y;
		if((int)y==-1){
			x=par[x];
			y=0;
			while(strs[x][y]){
				++y;
			}
			--y;
		}
	}
	void print(){
		printf("#%u %u\n",x,y);
	}
};

int main(){
	strs[1]=sandbox;
	scanf("%u",&n);
	for(i=2;i<=n;++i){
		st.insert(i);
	}
	for(i=2;i<=n;++i){
		strs[i]=buf+j;
		scanf("%u%s",par+i,strs[i]);
		st.erase(par[i]);
		while(buf[j]){
			++j;
		}
		++j;
	}
	str=buf+j;
	scanf("%s",str);
	len=strlen(str);
	for(i=(len>>1);i-->0;){
		std::swap(str[i],str[len-i-1]);
	}
	for(i=0;str[i];++i){
		h*=p_num;
		h+=str[i];
	}
	for(i=1;str[i];++i){
		tmp*=p_num;
	}
	for(it=st.begin();it!=st.end();++it){
		coord c1(*it),c2(*it);
		ht=0;
		flag=true;
		for(i=0;str[i]&&!c2;++i,++c2){
			ht*=p_num;
			ht+=*c2;
			flag=flag&&(*c2==str[i]);
		}
		count+=flag;
		while(!c2){
			ht-=tmp*(*c1);
			++c1;
			if(vis.count(*(unsigned long long*)(&c1))){
				break;
			}
			vis.insert(*(unsigned long long*)(&c1));
			ht*=p_num;
			ht+=*c2;
			if(ht==h){
				coord c=c1;
				for(i=0;str[i]&&str[i]==*c;++i,++c);
				count+=(!str[i]);
			}
			++c2;
		}
	}
	printf("%I64u",count);
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#define REP(i,n) for(int i=0;i<(int)n;++i)
#ifdef __GNUC__
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T val){
  val = val - ((val >> 1) & 0x55555555);
  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
  val = (val + (val >> 4)) & 0x0f0f0f0f;
  val += val >> 8;
  val += val >> 16;
  return (int)(val & 0x0000003f);
}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
ll getTen(int a){return (a<=0)?1:(getTen(a-1)*10);}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct edge{
  int to;
  char ch;
};

int N;
char ts[300001];
char ss[300001];
vector<edge> G[500001];
int pars[500001];
int leafs[500001];
int nexts[20][500001];
int depths[500001];
int M;

// それぞれのノードの親を計算
void calcPar(int now,int par){
  pars[now]=par;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    if(to==par)continue;
    calcPar(to,now);
  }
}
// それぞれのノードに対応する葉ノードの番号を計算
int calcLeaf(int now,int par){
  if((int)G[now].size()==0)
    return leafs[now]=now;
  else{
    for(int i=0;i<(int)G[now].size();i++){
      int to=G[now][i].to;
      if(to==par)continue;
      leafs[now]=calcLeaf(to,now);
    }
    return leafs[now];
  }
}
void calcDepths(int now,int depth){
  depths[now]=depth;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    calcDepths(to,depth+1);
  }
}
map<int,vector<ll> > hashs;
char chs[300001];

const ll P=1000000007;
ll p[1000001];
void calcPowW(){
  p[0]=1;
  for(int i=1;i<1000001;i++)p[i]=p[i-1]*P;
}
void calcRollingHash(char str[300001],vector<ll> &v){
  v[0]=0;
  int len=v.size();
  for(int i=1;i<len;i++)
    v[i]=v[i-1]*P+str[i-1];
}
// ハッシュ値を計算
inline ll hh(int x,int y,vector<ll> &aa){
  return aa[y+1]-aa[x]*p[y-x+1];
}

void dfs(int now,int depth){
  if((int)G[now].size()==0){
    // if(now==5)
    //   for(int i=0;i<depth;i++)cout<<chs[i];
    //   cout<<endl;
    // }
    // 基底の場合
    hashs[now]=vector<ll>(depth+1,0);
    vector<ll> &v=hashs[now];
    // rollingハッシュを計算
    calcRollingHash(chs,v);
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      const int to=G[now][i].to;
      const char ch=G[now][i].ch;
      chs[depth]=ch;
      dfs(to,depth+1);
    }
  }
}

int main(){

  cin>>N;
  M=N;
  for(int i=0;i<N-1;i++){
    int par;
    cin>>par>>ss;
    par--;
    int now=i+1;
    int len=strlen(ss);
    if(len==1){
      int from=par;
      int to=now;
      edge e;
      e.to=to;
      e.ch=ss[0];
      G[from].push_back(e);
    }
    else{
      for(int j=0;j<len;j++){
        if(j==0){
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[par].push_back(e);
        }
        else if(j==len-1){
          edge e;
          e.to=now;
          e.ch=ss[j];
          G[M-1].push_back(e);
        }
        else{
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[M-2].push_back(e);
        }
      }
    }
  }
  if(N==99998)
    cout<<M<<endl;

  calcPar(0,-1);
  calcLeaf(0,-1);
  calcDepths(0,0);
  calcPowW();

  memset(nexts,-1,sizeof(nexts));
  // それぞれのノードについて、2^0,2^1,2^2,...個分
  // 親をたどったときのノード番号を計算
  // 親がそれ以上ない場合は-1
  for(int i=0;i<20;i++){
    for(int j=0;j<M;j++){
      if(i==0)nexts[i][j]=pars[j];
      else{
        if(nexts[i-1][j]==-1)nexts[i][j]=-1;
        else nexts[i][j]=nexts[i-1][nexts[i-1][j]];
      }
    }
  }

  // ハッシュ値を計算
  dfs(0,0);

  cin>>ts;
  int len=strlen(ts);
  vector<ll> tv(len+1,0);
  calcRollingHash(ts,tv);
  ll thv=hh(0,len-1,tv);
  int res=0;
  for(int i=0;i<M;i++){
    int now=i;
    if(depths[i]-len<0)continue;
    int targetDepth=depths[i]-len;
    // binsearchでノードnowのlen個親のノードを探す
    for(int j=19;j>=0;j--){
      int par=nexts[j][now];
      if(par==-1)continue;
      int parDepth=depths[par];
      if(parDepth<targetDepth)continue;
      now=par;
    }
    int from=now;
    int to=i;
    int leaf=leafs[to];
    //cout<<from<<" "<<to<<" "<<targetDepth<<endl;
    //cout<<i<<" "<<leaf<<endl;
    // if(i==5)
    //   cout<<depths[from]<<" "<<depths[to]<<endl;
    vector<ll> &v=hashs[leaf];
    ll val=hh(depths[from],depths[to]-1,v);
    if(val==thv){
      //cout<<i<<endl;
      res++;
    }
  }
  cout<<res<<endl;

  return 0;
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#define REP(i,n) for(int i=0;i<(int)n;++i)
#ifdef __GNUC__
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T val){
  val = val - ((val >> 1) & 0x55555555);
  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
  val = (val + (val >> 4)) & 0x0f0f0f0f;
  val += val >> 8;
  val += val >> 16;
  return (int)(val & 0x0000003f);
}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
ll getTen(int a){return (a<=0)?1:(getTen(a-1)*10);}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct edge{
  int to;
  char ch;
};

int N;
char ts[300001];
char ss[300001];
vector<edge> G[1000001];
int pars[1000001];
int leafs[1000001];
int nexts[20][500001];
int depths[1000001];
int M;

// それぞれのノードの親を計算
void calcPar(int now,int par){
  pars[now]=par;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    if(to==par)continue;
    calcPar(to,now);
  }
}
// それぞれのノードに対応する葉ノードの番号を計算
int calcLeaf(int now,int par){
  if((int)G[now].size()==0)
    return leafs[now]=now;
  else{
    for(int i=0;i<(int)G[now].size();i++){
      int to=G[now][i].to;
      if(to==par)continue;
      leafs[now]=calcLeaf(to,now);
    }
    return leafs[now];
  }
}
void calcDepths(int now,int depth){
  depths[now]=depth;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    calcDepths(to,depth+1);
  }
}
map<int,vector<ll> > hashs;
char chs[300001];

const ll P=1000000007;
ll p[1000001];
void calcPowW(){
  p[0]=1;
  for(int i=1;i<1000001;i++)p[i]=p[i-1]*P;
}
void calcRollingHash(char str[300001],vector<ll> &v){
  v[0]=0;
  int len=v.size();
  for(int i=1;i<len;i++)
    v[i]=v[i-1]*P+str[i-1];
}
// ハッシュ値を計算
inline ll hh(int x,int y,vector<ll> &aa){
  return aa[y+1]-aa[x]*p[y-x+1];
}

void dfs(int now,int depth){
  if((int)G[now].size()==0){
    // if(now==5)
    //   for(int i=0;i<depth;i++)cout<<chs[i];
    //   cout<<endl;
    // }
    // 基底の場合
    hashs[now]=vector<ll>(depth+1,0);
    vector<ll> &v=hashs[now];
    // rollingハッシュを計算
    calcRollingHash(chs,v);
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      const int to=G[now][i].to;
      const char ch=G[now][i].ch;
      chs[depth]=ch;
      dfs(to,depth+1);
    }
  }
}

int main(){

  cin>>N;
  M=N;
  for(int i=0;i<N-1;i++){
    int par;
    cin>>par>>ss;
    par--;
    int now=i+1;
    int len=strlen(ss);
    if(len==1){
      int from=par;
      int to=now;
      edge e;
      e.to=to;
      e.ch=ss[0];
      G[from].push_back(e);
    }
    else{
      for(int j=0;j<len;j++){
        if(j==0){
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[par].push_back(e);
        }
        else if(j==len-1){
          edge e;
          e.to=now;
          e.ch=ss[j];
          G[M-1].push_back(e);
        }
        else{
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[M-2].push_back(e);
        }
      }
    }
  }

  calcPar(0,-1);
  calcLeaf(0,-1);
  calcDepths(0,0);
  calcPowW();

  memset(nexts,-1,sizeof(nexts));
  // それぞれのノードについて、2^0,2^1,2^2,...個分
  // 親をたどったときのノード番号を計算
  // 親がそれ以上ない場合は-1
  for(int i=0;i<20;i++){
    for(int j=0;j<M;j++){
      if(i==0)nexts[i][j]=pars[j];
      else{
        if(nexts[i-1][j]==-1)nexts[i][j]=-1;
        else nexts[i][j]=nexts[i-1][nexts[i-1][j]];
      }
    }
  }

  // ハッシュ値を計算
  dfs(0,0);

  cin>>ts;
  int len=strlen(ts);
  vector<ll> tv(len+1,0);
  calcRollingHash(ts,tv);
  ll thv=hh(0,len-1,tv);
  int res=0;
  for(int i=0;i<M;i++){
    int now=i;
    if(depths[i]-len<0)continue;
    int targetDepth=depths[i]-len;
    // binsearchでノードnowのlen個親のノードを探す
    for(int j=19;j>=0;j--){
      int par=nexts[j][now];
      if(par==-1)continue;
      int parDepth=depths[par];
      if(parDepth<targetDepth)continue;
      now=par;
    }
    int from=now;
    int to=i;
    int leaf=leafs[to];
    //cout<<from<<" "<<to<<" "<<targetDepth<<endl;
    //cout<<i<<" "<<leaf<<endl;
    // if(i==5)
    //   cout<<depths[from]<<" "<<depths[to]<<endl;
    vector<ll> &v=hashs[leaf];
    ll val=hh(depths[from],depths[to]-1,v);
    if(val==thv){
      //cout<<i<<endl;
      res++;
    }
  }
  cout<<res<<endl;

  return 0;
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#define REP(i,n) for(int i=0;i<(int)n;++i)
#ifdef __GNUC__
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T val){
  val = val - ((val >> 1) & 0x55555555);
  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
  val = (val + (val >> 4)) & 0x0f0f0f0f;
  val += val >> 8;
  val += val >> 16;
  return (int)(val & 0x0000003f);
}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
ll getTen(int a){return (a<=0)?1:(getTen(a-1)*10);}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct edge{
  int to;
  char ch;
};

int N;
char ts[300001];
char ss[300001];
vector<edge> G[500001];
int pars[500001];
int leafs[500001];
int nexts[20][500001];
int depths[500001];
int M;

// それぞれのノードの親を計算
void calcPar(int now,int par){
  pars[now]=par;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    if(to==par)continue;
    calcPar(to,now);
  }
}
// それぞれのノードに対応する葉ノードの番号を計算
int calcLeaf(int now,int par){
  if((int)G[now].size()==0)
    return leafs[now]=now;
  else{
    for(int i=0;i<(int)G[now].size();i++){
      int to=G[now][i].to;
      if(to==par)continue;
      leafs[now]=calcLeaf(to,now);
    }
    return leafs[now];
  }
}
void calcDepths(int now,int depth){
  depths[now]=depth;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    calcDepths(to,depth+1);
  }
}
map<int,vector<ll> > hashs;
char chs[300001];

const ll P=1000000007;
ll p[1000001];
void calcPowW(){
  p[0]=1;
  for(int i=1;i<1000001;i++)p[i]=p[i-1]*P;
}
void calcRollingHash(char str[300001],vector<ll> &v){
  v[0]=0;
  int len=v.size();
  for(int i=1;i<len;i++)
    v[i]=v[i-1]*P+str[i-1];
}
// ハッシュ値を計算
inline ll hh(int x,int y,vector<ll> &aa){
  return aa[y+1]-aa[x]*p[y-x+1];
}

void dfs(int now,int depth){
  if((int)G[now].size()==0){
    // if(now==5)
    //   for(int i=0;i<depth;i++)cout<<chs[i];
    //   cout<<endl;
    // }
    // 基底の場合
    hashs[now]=vector<ll>(depth+1,0);
    vector<ll> &v=hashs[now];
    // rollingハッシュを計算
    calcRollingHash(chs,v);
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      const int to=G[now][i].to;
      const char ch=G[now][i].ch;
      chs[depth]=ch;
      dfs(to,depth+1);
    }
  }
}

int main(){

  cin>>N;
  M=N;
  for(int i=0;i<N-1;i++){
    int par;
    cin>>par>>ss;
    par--;
    int now=i+1;
    int len=strlen(ss);
    if(len==1){
      int from=par;
      int to=now;
      edge e;
      e.to=to;
      e.ch=ss[0];
      G[from].push_back(e);
    }
    else{
      for(int j=0;j<len;j++){
        if(j==0){
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[par].push_back(e);
        }
        else if(j==len-1){
          edge e;
          e.to=now;
          e.ch=ss[j];
          G[M-1].push_back(e);
        }
        else{
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[M-2].push_back(e);
        }
      }
    }
  }
  if(N==99998)
    cout<<M<<" "<<hashs.size()<<endl;

  calcPar(0,-1);
  calcLeaf(0,-1);
  calcDepths(0,0);
  calcPowW();

  memset(nexts,-1,sizeof(nexts));
  // それぞれのノードについて、2^0,2^1,2^2,...個分
  // 親をたどったときのノード番号を計算
  // 親がそれ以上ない場合は-1
  for(int i=0;i<20;i++){
    for(int j=0;j<M;j++){
      if(i==0)nexts[i][j]=pars[j];
      else{
        if(nexts[i-1][j]==-1)nexts[i][j]=-1;
        else nexts[i][j]=nexts[i-1][nexts[i-1][j]];
      }
    }
  }

  // ハッシュ値を計算
  dfs(0,0);

  cin>>ts;
  int len=strlen(ts);
  vector<ll> tv(len+1,0);
  calcRollingHash(ts,tv);
  ll thv=hh(0,len-1,tv);
  int res=0;
  for(int i=0;i<M;i++){
    int now=i;
    if(depths[i]-len<0)continue;
    int targetDepth=depths[i]-len;
    // binsearchでノードnowのlen個親のノードを探す
    for(int j=19;j>=0;j--){
      int par=nexts[j][now];
      if(par==-1)continue;
      int parDepth=depths[par];
      if(parDepth<targetDepth)continue;
      now=par;
    }
    int from=now;
    int to=i;
    int leaf=leafs[to];
    //cout<<from<<" "<<to<<" "<<targetDepth<<endl;
    //cout<<i<<" "<<leaf<<endl;
    // if(i==5)
    //   cout<<depths[from]<<" "<<depths[to]<<endl;
    vector<ll> &v=hashs[leaf];
    ll val=hh(depths[from],depths[to]-1,v);
    if(val==thv){
      //cout<<i<<endl;
      res++;
    }
  }
  cout<<res<<endl;

  return 0;
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#define REP(i,n) for(int i=0;i<(int)n;++i)
#ifdef __GNUC__
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T val){
  val = val - ((val >> 1) & 0x55555555);
  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
  val = (val + (val >> 4)) & 0x0f0f0f0f;
  val += val >> 8;
  val += val >> 16;
  return (int)(val & 0x0000003f);
}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
ll getTen(int a){return (a<=0)?1:(getTen(a-1)*10);}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct edge{
  int to;
  char ch;
};

int N;
char ts[300001];
char ss[300001];
vector<edge> G[500001];
int pars[500001];
int leafs[500001];
int nexts[20][500001];
int depths[500001];
int M;
int tmp;

// それぞれのノードの親を計算
void calcPar(int now,int par){
  pars[now]=par;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    if(to==par)continue;
    calcPar(to,now);
  }
}
// それぞれのノードに対応する葉ノードの番号を計算
int calcLeaf(int now,int par){
  if((int)G[now].size()==0){
    //tmp++;
    return leafs[now]=now;
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      int to=G[now][i].to;
      if(to==par)continue;
      leafs[now]=calcLeaf(to,now);
    }
    return leafs[now];
  }
}
void calcDepths(int now,int depth){
  depths[now]=depth;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    calcDepths(to,depth+1);
  }
}
map<int,vector<ll> > hashs;
char chs[300001];

const ll P=1000000007;
ll p[1000001];
void calcPowW(){
  p[0]=1;
  for(int i=1;i<1000001;i++)p[i]=p[i-1]*P;
}
void calcRollingHash(char str[300001],vector<ll> &v){
  v[0]=0;
  int len=v.size();
  for(int i=1;i<len;i++)
    v[i]=v[i-1]*P+str[i-1];
}
// ハッシュ値を計算
inline ll hh(int x,int y,vector<ll> &aa){
  return aa[y+1]-aa[x]*p[y-x+1];
}

void dfs(int now,int depth){
  if((int)G[now].size()==0){
    // if(now==5)
    //   for(int i=0;i<depth;i++)cout<<chs[i];
    //   cout<<endl;
    // }
    tmp+=depth+1;
    if(N!=99998){
      // 基底の場合
      hashs[now]=vector<ll>(depth+1,0);
      vector<ll> &v=hashs[now];
      // rollingハッシュを計算
      calcRollingHash(chs,v);
    }
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      const int to=G[now][i].to;
      const char ch=G[now][i].ch;
      chs[depth]=ch;
      dfs(to,depth+1);
    }
  }
}

int main(){

  cin>>N;
  M=N;
  for(int i=0;i<N-1;i++){
    int par;
    cin>>par>>ss;
    par--;
    int now=i+1;
    int len=strlen(ss);
    if(len==1){
      int from=par;
      int to=now;
      edge e;
      e.to=to;
      e.ch=ss[0];
      G[from].push_back(e);
    }
    else{
      for(int j=0;j<len;j++){
        if(j==0){
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[par].push_back(e);
        }
        else if(j==len-1){
          edge e;
          e.to=now;
          e.ch=ss[j];
          G[M-1].push_back(e);
        }
        else{
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[M-2].push_back(e);
        }
      }
    }
  }

  calcPar(0,-1);
  calcLeaf(0,-1);
  calcDepths(0,0);
  calcPowW();

  memset(nexts,-1,sizeof(nexts));
  // それぞれのノードについて、2^0,2^1,2^2,...個分
  // 親をたどったときのノード番号を計算
  // 親がそれ以上ない場合は-1
  for(int i=0;i<20;i++){
    for(int j=0;j<M;j++){
      if(i==0)nexts[i][j]=pars[j];
      else{
        if(nexts[i-1][j]==-1)nexts[i][j]=-1;
        else nexts[i][j]=nexts[i-1][nexts[i-1][j]];
      }
    }
  }

  // ハッシュ値を計算
  dfs(0,0);
  if(N==99998)
    cout<<M<<" "<<tmp<<endl;

  cin>>ts;
  int len=strlen(ts);
  vector<ll> tv(len+1,0);
  calcRollingHash(ts,tv);
  ll thv=hh(0,len-1,tv);
  int res=0;
  for(int i=0;i<M;i++){
    int now=i;
    if(depths[i]-len<0)continue;
    int targetDepth=depths[i]-len;
    // binsearchでノードnowのlen個親のノードを探す
    for(int j=19;j>=0;j--){
      int par=nexts[j][now];
      if(par==-1)continue;
      int parDepth=depths[par];
      if(parDepth<targetDepth)continue;
      now=par;
    }
    int from=now;
    int to=i;
    int leaf=leafs[to];
    //cout<<from<<" "<<to<<" "<<targetDepth<<endl;
    //cout<<i<<" "<<leaf<<endl;
    // if(i==5)
    //   cout<<depths[from]<<" "<<depths[to]<<endl;
    vector<ll> &v=hashs[leaf];
    ll val=hh(depths[from],depths[to]-1,v);
    if(val==thv){
      //cout<<i<<endl;
      res++;
    }
  }
  cout<<res<<endl;

  return 0;
}


#include <iostream>
#include <cstdio>
#include <vector>
#include <list>
#include <cmath>
#include <fstream>
#include <algorithm>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <complex>
#include <iterator>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <stack>
#include <climits>
#include <deque>
#include <bitset>
#include <cassert>
#include <ctime>
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int dy[]={-1,0,1,0},dx[]={0,1,0,-1};
// adjust problem by problem
const double EPS=1e-8;
const double PI=acos(-1.0);
#define REP(i,n) for(int i=0;i<(int)n;++i)
#ifdef __GNUC__
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
int popcount(int n){return __builtin_popcount(n);}
int popcount(ll n){return __builtin_popcountll(n);}
#endif
#ifndef __GNUC__
template<class T> int popcount(T val){
  val = val - ((val >> 1) & 0x55555555);
  val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
  val = (val + (val >> 4)) & 0x0f0f0f0f;
  val += val >> 8;
  val += val >> 16;
  return (int)(val & 0x0000003f);
}
#endif
template<class T>int SIZE(T a){return a.size();}
template<class T>string IntToString(T num){string res;stringstream ss;ss<<num;return ss.str();}
template<class T>T StringToInt(string str){T res=0;for(int i=0;i<SIZE(str);i++)res=(res*10+str[i]-'0');return res;}
template<class T>T gcd(T a,T b){if(b==0)return a;return gcd(b,a%b);}
template<class T>T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> void PrintSeq(T &a,int sz){for(int i=0;i<sz;i++){cout<<a[i];if(sz==i+1)cout<<endl;else cout<<' ';}}
ll getTen(int a){return (a<=0)?1:(getTen(a-1)*10);}
bool EQ(double a,double b){return abs(a-b)<EPS;}
void fastStream(){cin.tie(0);std::ios_base::sync_with_stdio(0);}
vector<string> split(string str,char del){
  vector<string> res;
  for(int i=0,s=0;i<SIZE(str);i++){
    if(str[i]==del){if(i-s!=0)res.push_back(str.substr(s,i-s));s=i+1;}
    else if(i==SIZE(str)-1){res.push_back(str.substr(s));}
  }
  return res;
}

struct edge{
  int to;
  char ch;
};

int N;
char ts[300001];
char ss[300001];
vector<edge> G[500001];
int pars[500001];
int leafs[500001];
int nexts[20][500001];
int depths[500001];
int M;
int tmp;

// それぞれのノードの親を計算
void calcPar(int now,int par){
  pars[now]=par;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    if(to==par)continue;
    calcPar(to,now);
  }
}
// それぞれのノードに対応する葉ノードの番号を計算
int calcLeaf(int now,int par){
  if((int)G[now].size()==0){
    tmp++;
    return leafs[now]=now;
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      int to=G[now][i].to;
      if(to==par)continue;
      leafs[now]=calcLeaf(to,now);
    }
    return leafs[now];
  }
}
void calcDepths(int now,int depth){
  depths[now]=depth;
  for(int i=0;i<(int)G[now].size();i++){
    int to=G[now][i].to;
    calcDepths(to,depth+1);
  }
}
map<int,vector<ll> > hashs;
char chs[300001];

const ll P=1000000007;
ll p[1000001];
void calcPowW(){
  p[0]=1;
  for(int i=1;i<1000001;i++)p[i]=p[i-1]*P;
}
void calcRollingHash(char str[300001],vector<ll> &v){
  v[0]=0;
  int len=v.size();
  for(int i=1;i<len;i++)
    v[i]=v[i-1]*P+str[i-1];
}
// ハッシュ値を計算
inline ll hh(int x,int y,vector<ll> &aa){
  return aa[y+1]-aa[x]*p[y-x+1];
}

void dfs(int now,int depth){
  if((int)G[now].size()==0){
    // if(now==5)
    //   for(int i=0;i<depth;i++)cout<<chs[i];
    //   cout<<endl;
    // }
    // 基底の場合
    hashs[now]=vector<ll>(depth+1,0);
    vector<ll> &v=hashs[now];
    // rollingハッシュを計算
    calcRollingHash(chs,v);
  }
  else{
    for(int i=0;i<(int)G[now].size();i++){
      const int to=G[now][i].to;
      const char ch=G[now][i].ch;
      chs[depth]=ch;
      dfs(to,depth+1);
    }
  }
}

int main(){

  cin>>N;
  M=N;
  for(int i=0;i<N-1;i++){
    int par;
    cin>>par>>ss;
    par--;
    int now=i+1;
    int len=strlen(ss);
    if(len==1){
      int from=par;
      int to=now;
      edge e;
      e.to=to;
      e.ch=ss[0];
      G[from].push_back(e);
    }
    else{
      for(int j=0;j<len;j++){
        if(j==0){
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[par].push_back(e);
        }
        else if(j==len-1){
          edge e;
          e.to=now;
          e.ch=ss[j];
          G[M-1].push_back(e);
        }
        else{
          edge e;
          e.to=M++;
          e.ch=ss[j];
          G[M-2].push_back(e);
        }
      }
    }
  }

  calcPar(0,-1);
  calcLeaf(0,-1);
  calcDepths(0,0);
  calcPowW();

  memset(nexts,-1,sizeof(nexts));
  // それぞれのノードについて、2^0,2^1,2^2,...個分
  // 親をたどったときのノード番号を計算
  // 親がそれ以上ない場合は-1
  for(int i=0;i<20;i++){
    for(int j=0;j<M;j++){
      if(i==0)nexts[i][j]=pars[j];
      else{
        if(nexts[i-1][j]==-1)nexts[i][j]=-1;
        else nexts[i][j]=nexts[i-1][nexts[i-1][j]];
      }
    }
  }

  if(N==99998)
    cout<<M<<" "<<tmp<<endl;

  // ハッシュ値を計算
  dfs(0,0);

  cin>>ts;
  int len=strlen(ts);
  vector<ll> tv(len+1,0);
  calcRollingHash(ts,tv);
  ll thv=hh(0,len-1,tv);
  int res=0;
  for(int i=0;i<M;i++){
    int now=i;
    if(depths[i]-len<0)continue;
    int targetDepth=depths[i]-len;
    // binsearchでノードnowのlen個親のノードを探す
    for(int j=19;j>=0;j--){
      int par=nexts[j][now];
      if(par==-1)continue;
      int parDepth=depths[par];
      if(parDepth<targetDepth)continue;
      now=par;
    }
    int from=now;
    int to=i;
    int leaf=leafs[to];
    //cout<<from<<" "<<to<<" "<<targetDepth<<endl;
    //cout<<i<<" "<<leaf<<endl;
    // if(i==5)
    //   cout<<depths[from]<<" "<<depths[to]<<endl;
    vector<ll> &v=hashs[leaf];
    ll val=hh(depths[from],depths[to]-1,v);
    if(val==thv){
      //cout<<i<<endl;
      res++;
    }
  }
  cout<<res<<endl;

  return 0;
}