#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const ull mod=(1ull<<61)-1,base=233;
inline ull mult(ull a,ull b)
{
	ull l1=(unsigned int)a,h1=a>>32,l2=(unsigned int)b,h2=b>>32;
	ull l=l1*l2,m=l1*h2+l2*h1,h=h1*h2;
	ull ret=(l&mod)+(l>>61)+(h<<3)+(m>>29)+(m<<35>>3)+1;
	ret=(ret&mod)+(ret>>61);
	ret=(ret&mod)+(ret>>61);
	return ret-1;
}
inline ull add(ull a,ull b)
{
	if((a+=b)>=mod)a-=mod;
	return a;
}
inline ull dec(ull a,ull b)
{
	return add(a,mod-b);
}
ull hs[100010][110],pw[100010];
int n,Q,st[100010][17],dep[100010];
char fc[100010];
inline int lca(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);
	for(int i=16;i>=0;i--)
		if(dep[st[x][i]]>=dep[y])x=st[x][i];
	if(x==y)return x;
	for(int i=16;i>=0;i--)
		if(st[x][i]!=st[y][i])x=st[x][i],y=st[y][i];
	return st[x][0];
}
inline int jump(int p,int t)
{
	for(int i=16;i>=0;i--)if((t>>i)&1)p=st[p][i];
	return p;
}
int ans[100010];
vector<pair<int,int> > q[100010];
vector<pair<int,char> > v[100010];
unordered_map<ull,int> cnt;
string s[200010];
ull vl[200010];
int len[200010];
void dfs1(int np,int fath,char ic)
{
	dep[np]=dep[fath]+1;
	st[np][0]=fath;
	fc[np]=ic;
	for(int i=1;i<17;i++)st[np][i]=st[st[np][i-1]][i-1];
	hs[np][0]=0;
	for(int i=1;i<=100&&i<dep[np];i++)hs[np][i]=add(mult(ic-'a'+1,pw[i-1]),hs[fath][i-1]);
	for(auto &x:v[np])
	{
		if(x.first==fath)continue;
		dfs1(x.first,np,x.second);
	}
}
inline ull gethash(const string &s)
{
	ull h=0;
	for(int i=0;i<s.size();i++)
		h=add(mult(h,base),s[i]-'a'+1);
	return h;
}
int cmp(const vector<char> &a,ull key,int len)
{
	if(a.size()>len)return 0;
	ull h=0;
	int ret=0;
	for(int i=0;i<len-1;i++)h=add(mult(h,base),a[i]-'a'+1);
	for(int i=len-1;i<a.size();i++)
	{
		h=add(mult(h,base),a[i]-'a'+1);
		ret+=(h==key);
		h=dec(h,mult(pw[len-1],a[i-len+1]-'a'+1));
	}
	return ret;
}
void dfs2(int np,int fath,int l)
{
	if(dep[np]>l)cnt[hs[np][l]]++;
//	for(int i=1;i<dep[np]&&i<=100;i++)cnt[hs[np][i]]++;
	for(auto &x:q[np])
	{
		if(len[x.first]==l)
		{
			if(x.second==1)ans[x.first>>1]+=cnt[vl[x.first]];
			else ans[x.first>>1]-=cnt[vl[x.first]];
		}
	}
	for(auto &x:v[np])
		if(x.first!=fath)dfs2(x.first,np,l);
	if(dep[np]>l)cnt[hs[np][l]]--;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)
	{
		int a,b;
		char s[5];
		scanf("%d%d%s",&a,&b,s);
		v[a].push_back(make_pair(b,s[0]));
		v[b].push_back(make_pair(a,s[0]));
	}
	pw[0]=1;
	for(int i=1;i<=100;i++)pw[i]=mult(pw[i-1],base);
	dfs1(1,0,'a');
	scanf("%d",&Q);
	for(int i=1,a,b;i<=Q;i++)
	{
		scanf("%d%d",&a,&b);
		cin>>s[i*2];
		int cl=s[i*2].size();
		s[i*2+1]=s[i*2];
		reverse(s[i*2+1].begin(),s[i*2+1].end());
		vl[i*2]=gethash(s[i*2]);
		vl[i*2+1]=gethash(s[i*2+1]);
		len[i*2]=s[i*2].size();
		len[i*2+1]=s[i*2+1].size();
		int L=lca(a,b);
		vector<char> v1,v2;
		int p;
		if(dep[a]-dep[L]<cl-1)p=a;
		else p=jump(a,dep[a]-dep[L]-(cl-1));
		if(a!=p)
		{
			q[a].push_back(make_pair(i*2,1));
			q[p].push_back(make_pair(i*2,-1));
		}
		while(p!=L)v1.push_back(fc[p]),p=st[p][0];
		if(dep[b]-dep[L]<cl)p=b;
		else p=jump(b,dep[b]-dep[L]-(cl-1));
		if(b!=p)
		{
			q[b].push_back(make_pair(i*2+1,1));
			q[p].push_back(make_pair(i*2+1,-1));
		}
		while(p!=L)v2.push_back(fc[p]),p=st[p][0];
		reverse(v2.begin(),v2.end());
		v1.insert(v1.end(),v2.begin(),v2.end());
		ans[i]=cmp(v1,vl[i<<1],s[i*2].size());
	}
	for(int i=1;i<=100;i++)
	{
		cnt.clear();
		dfs2(1,0,i);
	}
//	dfs2(1,0);
	for(int i=1;i<=Q;i++)printf("%d\n",ans[i]);
	return 0;
}


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
unordered_map<pi,int,hsh<pi>> t[101];
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[i+1][toadd] ++;
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            pi res = H.getHsh(s);
            if (t[sz(s)].find(res) != t[sz(s)].end()) ans[a[0]] += a[1]*t[sz(s)][res];
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[i+1][toadd] --;
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    FOR(i,1,101) t[i].reserve(MX);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
gp_hash_table<pi,int,hsh<pi>> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u, bool sgn) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] ++;
            } else {
                if (i+1 > 50) t[toadd] ++;
            }
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            pi res = H.getHsh(s);
            if (sgn == 0) {
                if (sz(s) <= 50) {
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            } else {
                if (sz(s) > 50) {
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            }
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f,sgn);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] --;
            } else {
                if (i+1 > 50) t[toadd] --;
            }
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    // t.reserve(50*MX);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1,0);
    t.clear();
    L.dfs2(1,1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

template<int MX> struct tri {
    array<int,26> trie[MX];
    int nex = 0, sz[MX];

    tri() {
        memset(sz,0,sizeof sz);
    }

    void ins(string x, int a = 1) {
        int cur = 0;
        F0R(i,sz(x)) {
            sz[cur] += a;
            if (!trie[cur][x[i]-'a']) trie[cur][x[i]-'a'] = ++nex;
            cur = trie[cur][x[i]-'a'];
        }
        sz[cur] += a;
    }

    int query(string x) { // compute max xor
        int cur = 0;
        F0R(i,sz(x)) {
            if (!trie[cur][x[i]-'a']) return 0;
            cur = trie[cur][x[i]-'a'];
        }
        return sz[cur];
    }
};

int N, Q, ans[MX];
string c[MX];
tri<100*MX> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        string toadd;
        int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += let[cur]; cur = par[0][cur];
        }
        t.ins(toadd,1);
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            ans[a[0]] += a[1]*t.query(s);
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        t.ins(toadd,-1);
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

    template<class a, class b> b get(um<a,b>& u, a x) {
        if (u.find(x) == u.end()) return 0;
        return u[x];
    }
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
um<pi,int> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] ++;
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            ans[a[0]] += a[1]*get(t,H.getHsh(s));
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] --;
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
map<pi,int> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] ++;
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            pi res = H.getHsh(s);
            if (t.count(res)) ans[a[0]] += a[1]*t[res];
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] --;
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

    template<class a, class b> b get(um<a,b>& u, a x) {
        if (u.find(x) == u.end()) return 0;
        return u[x];
    }
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
um<pi,int> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] ++;
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            ans[a[0]] += a[1]*get(t,H.getHsh(s));
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] --;
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
unordered_map<pi,int,hsh<pi>> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u, bool sgn) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] ++;
            } else {
                if (i+1 > 50) t[toadd] ++;
            }
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            pi res = H.getHsh(s);
            if (sgn == 0) {
                if (sz(s) <= 50) {
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            } else {
                if (sz(s) > 50) {
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            }
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f,sgn);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] --;
            } else {
                if (i+1 > 50) t[toadd] --;
            }
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    t.reserve(50*MX);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1,0);
    t.clear();
    L.dfs2(1,1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
unordered_map<pi,int,hsh<pi>> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] ++;
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            string s = c[a[0]];
            if (a[2]) reverse(all(s));
            pi res = H.getHsh(s);
            if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            t[toadd] --;
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    t.reserve(100*MX);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#pragma GCC optimize ("O3")
#pragma GCC target ("sse4")

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

using namespace std;
using namespace __gnu_pbds;
using namespace __gnu_cxx;

typedef long long ll;
typedef long double ld;
typedef complex<ld> cd;

typedef pair<int, int> pi;
typedef pair<ll,ll> pl;
typedef pair<ld,ld> pd;

typedef vector<int> vi;
typedef vector<ld> vd;
typedef vector<ll> vl;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<cd> vcd;

template <class T> using Tree = tree<T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>;

#define FOR(i, a, b) for (int i=a; i<(b); i++)
#define F0R(i, a) for (int i=0; i<(a); i++)
#define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
#define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)

#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define f first
#define s second
#define lb lower_bound
#define ub upper_bound
#define all(x) x.begin(), x.end()

const int MOD = 1000000007;
const ll INF = 1e18;
const int MX = 100001;

namespace io {
    void setIn(string s) { freopen(s.c_str(),"r",stdin); }
    void setOut(string s) { freopen(s.c_str(),"w",stdout); }
    void setIO(string s = "") {
        ios_base::sync_with_stdio(0); cin.tie(0);
        if (sz(s)) { setIn(s+".in"), setOut(s+".out"); }
    }

    // double input seems slow on CF
    void re(double& x) { string t; cin >> t; x = stod(t); }
    void re(ld& x) { string t; cin >> t; x = stold(t); }
    template<class T> void re(T& x) { cin >> x; }
    template<class Arg, class... Args> void re(Arg& first, Args&... rest) { re(first); re(rest...); }

	// pair
	template<class T1, class T2> istream& operator>>(istream& is, pair<T1,T2>& p) {
	    is >> p.f >> p.s;
	    return is;
	}
	template<class T1, class T2> ostream& operator<<(ostream& os, const pair<T1,T2>& a) {
	    os << '{' << a.f << ", " << a.s << '}';
	    return os;
	}

    // vector
	template<class T> istream& operator>>(istream& is, vector<T>& a) {
	    int sz; is >> sz; a.resize(sz);
	    F0R(i,sz) is >> a[i];
	    return is;
	}
	template<class T> ostream& operator<<(ostream& os, const vector<T>& a) {
	    os << "{";
	    F0R(i,sz(a)) {
	        if (i) os << ", ";
	        os << a[i];
	    }
	    os << "}";
	    return os;
	}
}

using namespace io;

namespace modOp {
    ll po (ll b, ll p) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD; }
    ll inv (ll b) { return po(b,MOD-2); }

    ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
        a %= b;
        if (a <= 1) return a;
        ll i = inv(b%a,a);
        ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
        if (tmp < 0) tmp += b;
        return tmp;
    }

    int ad(int a, int b) { return (a+b)%MOD; }
    int sub(int a, int b) { return (a-b+MOD)%MOD; }
    int mul(int a, int b) { return (ll)a*b%MOD; }

    int AD(int& a, int b) { return a = ad(a,b); }
    int SUB(int& a, int b) { return a = sub(a,b); }
    int MUL(int& a, int b) { return a = mul(a,b); }
}

using namespace modOp;

namespace pairOp {
    template<class T> T operator+=(T& l, const T& r) { return l = l+r; }
    template<class T> T operator-=(T& l, const T& r) { return l = l-r; }
    template<class T> T operator*=(T& l, const T& r) { return l = l*r; }

	pi operator+(const pi& l, const pi& r) { return {ad(l.f,r.f),ad(l.s,r.s)}; }
	pi operator-(const pi& l, const pi& r) { return {sub(l.f,r.f),sub(l.s,r.s)}; }
	pi operator*(const pi& l, const pi& r) { return {mul(l.f,r.f),mul(l.s,r.s)}; }
	pi operator*(const pi& l, const int& r) { return l*pi(r,r); }
	pi operator*(const int& r, const pi& l) { return l*r; }
	pi operator*=(pi& l, const int& r) { return l = l*r; }
}

using namespace pairOp;

struct strhsh {
    vpi po, ipo;
    pi base = mp(948392576,573928192), invbase; // probably want to randomize base

    strhsh() {
        invbase = {inv(base.f),inv(base.s)};
        po.resize(MX), ipo.resize(MX);

        po[0] = ipo[0] = {1,1};
        FOR(i,1,MX) po[i] = po[i-1]*base, ipo[i] = ipo[i-1]*invbase;
    }

    pi getHsh(string s) {
        pi res = {0,0};
        F0R(i,sz(s)) res += po[i]*(s[i]-'a'+1);
        return res;
    }
};

strhsh H;

namespace mapOp {
    const int tmp = chrono::high_resolution_clock::now().time_since_epoch().count();

    template<class T> struct hsh {
        size_t operator()(const T& x) const {
            return (ll)MOD*x.f+x.s;
        }
    };

    template<class a, class b> using um = gp_hash_table<a,b,hsh<a>>;

}

template<class T, class a, class b> b get(T& u, a x) {
    if (u.find(x) == u.end()) return 0;
    return u[x];
}

using namespace mapOp;

int N, Q, ans[MX];
string c[MX];
unordered_map<pi,int,hsh<pi>> t;
vector<array<int,3>> query[MX];

template<int SZ> struct LCA {
    const int MAXK = 32-__builtin_clz(SZ);

    int N, R = 1; // vertices from 1 to N, R = root
    vector<pair<int,char>> adj[SZ];
    int par[32-__builtin_clz(SZ)][SZ], depth[SZ];
    char let[SZ];
    pi hsh[SZ][2];

    void addEdge(int u, int v, char c) {
        adj[u].pb({v,c}), adj[v].pb({u,c});
    }

    void dfs(int u, int prev, char _let = 0) {
        par[0][u] = prev; let[u] = _let;

        depth[u] = depth[prev]+1;
        if (u != 1) {
            hsh[u][0] = hsh[par[0][u]][0]+H.po[depth[u]]*(let[u]-'a'+1);
            hsh[u][1] = hsh[par[0][u]][1]+H.ipo[depth[u]]*(let[u]-'a'+1);
        }

        for (auto v: adj[u]) if (v.f != prev) dfs(v.f, u, v.s);
    }

    void dfs2(int u, bool sgn) {
        pi toadd = {0,0}; int cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] ++;
                else break;
            } else {
                if (i+1 > 50) t[toadd] ++;
            }
        }
        for (auto a: query[u]) { // pos, sign, reverse or not
            if (sgn == 0) {
                if (sz(c[a[0]]) <= 50) {
                    string s = c[a[0]];
                    if (a[2]) reverse(all(s));
                    pi res = H.getHsh(s);
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            } else {
                if (sz(c[a[0]]) > 50) {
                    string s = c[a[0]];
                    if (a[2]) reverse(all(s));
                    pi res = H.getHsh(s);
                    if (t.find(res) != t.end()) ans[a[0]] += a[1]*t[res];
                }
            }
        }
        for (auto v: adj[u]) if (v.f != par[0][u]) dfs2(v.f,sgn);
        toadd = {0,0};
        cur = u;
        F0R(i,100) {
            if (cur == 1) break;
            toadd += (let[cur]-'a'+1)*H.po[i]; cur = par[0][cur];
            if (sgn == 0) {
                if (i+1 <= 50) t[toadd] --;
                else break;
            } else {
                if (i+1 > 50) t[toadd] --;
            }
        }
    }

    void init(int _N) {
    	N = _N;
        dfs(R, 0);
        FOR(k,1,MAXK) FOR(i,1,N+1)
            par[k][i] = par[k-1][par[k-1][i]];
    }

    int getPar(int u, int d) {
        F0Rd(k,MAXK) if (d&(1<<k)) u = par[k][u];
        return u;
    }

    int lca(int u, int v){
        if (depth[u] < depth[v]) swap(u,v);

        F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))  u = par[k][u];
        F0Rd(k,MAXK) if (par[k][u] != par[k][v]) u = par[k][u], v = par[k][v];

        if(u != v) u = par[0][u], v = par[0][v];
        return u;
    }

    int dist(int u, int v) {
        return depth[u]+depth[v]-2*depth[lca(u,v)];
    }
};

LCA<MX> L;

void naive(int A, int B, int x, int ind) {
    pi t = H.getHsh(c[ind]);
    vi Apath, Bpath;
    while (A != x) {
        Apath.pb(A);
        A = L.par[0][A];
    }
    while (B != x) {
        Bpath.pb(B);
        B = L.par[0][B];
    }
    Apath.pb(x), Bpath.pb(x);
    reverse(all(Apath)); reverse(all(Bpath));

    F0Rd(i,sz(Apath)) if (sz(c[ind])-i < sz(Bpath)) {
        pi tmp = (L.hsh[Apath[i]][1]-L.hsh[x][1])*H.po[L.depth[Apath[i]]];
        tmp += H.po[i]*H.ipo[L.depth[x]+1]*(L.hsh[Bpath[sz(c[ind])-i]][0]-L.hsh[x][0]);
        if (tmp == t) ans[ind] ++;
    }
}

int main() {
    setIO(); re(N);
    F0R(i,N-1) {
        int a,b; char c; re(a,b,c);
        L.addEdge(a,b,c);
    }
    L.init(N);
    t.reserve(50*MX);
    re(Q);
    F0R(i,Q) {
        int a,b; re(a,b,c[i]);
        int x = L.lca(a,b);
        //cout << a << " " << b << " " << x << " " << c[i] << "\n";
        if (L.depth[a]-L.depth[x] >= sz(c[i])) {
            query[a].pb({i,1,0});
            int A = L.getPar(a,L.depth[a]-L.depth[x]-sz(c[i])+1);
            query[A].pb({i,-1,0});
            a = A;
        }
        if (L.depth[b]-L.depth[x] >= sz(c[i])) {
            query[b].pb({i,1,1});
            int B = L.getPar(b,L.depth[b]-L.depth[x]-sz(c[i])+1);
            query[B].pb({i,-1,1});
            b = B;
        }
        naive(a,b,x,i);
    }
    L.dfs2(1,0);
    t.clear();
    L.dfs2(1,1);
    F0R(i,Q) cout << ans[i] << "\n";
}

/*
* (Actually read this pls)
    * Rlly bad errors: int overflow, array bounds
    * Less bad errors: special cases (n=1?), set tle
    * Common sense: do smth instead of nothing
*/


#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#define pll pair<long long,long long>
#define plli pair< pll,int>
#define N_ 101000
using namespace std;
vector<int>E[N_], L[N_];
vector<plli>V[110];
int pL[N_], n, Dep[N_], par[N_][20], Num[N_], cnt, C[N_], PPP[N_], ReNum[N_];
long long BS = 26, Mod[2] = { 100000000000007,100000000000009 }, po[N_][2];
void DFS(int a, int pp) {
	int i;
	C[a]++;
	par[a][0] = pp;
	for (i = 0; i < 18; i++)par[a][i+1] = par[par[a][i]][i];
	for (i = 0; i < E[a].size();i++) {
		int x = E[a][i];
		if (x == pp)continue;
		Dep[x] = Dep[a] + 1;
		pL[x] = L[a][i];
		DFS(x, a);
		C[a] += C[x];
	}
}
int Up(int a, int d) {
	int i = 0;
	while (d) {
		if (d & 1)a = par[a][i];
		i++; d >>= 1;
	}
	return a;
}
void HLD(int a, int ppp) {
	PPP[a] = ppp;
	Num[a] = ++cnt;
	ReNum[cnt] = a;
	int Mx = -1, pv = -1;
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (Mx < C[x])Mx = C[x], pv = x;
	}
	if (pv == -1) {
		return;
	}
	HLD(pv, ppp);
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (x != pv)HLD(x, x);
	}
}
int LCA(int a, int b) {
	if (Dep[a] < Dep[b])return LCA(b, a);
	a = Up(a, Dep[a] - Dep[b]);
	int i;
	for (i = 17; i >= 0; i--)if (par[a][i] != par[b][i])a = par[a][i], b = par[b][i];
	if (a != b)a = par[a][0];
	return a;
}
char p[110];
int m, w[110], q[220];
int Get(int b, int e, int z1, int z2) {
	return lower_bound(V[m].begin(), V[m].end(), plli(pll(z1,z2),e+1)) - lower_bound(V[m].begin(), V[m].end(), plli(pll(z1, z2),b));
}
int Go(int a, int pp, int z1, int z2) {
	int i;
	int l = Dep[a] - Dep[pp];
	if (l < m)return 0;
	int rp = Up(a, l - m), res = 0;
	while (1) {
		int t = PPP[a];
		if (Dep[t] <= Dep[rp]) {
			res += Get(Num[rp], Num[a], z1,z2);
			break;
		}
		else {
			res += Get(Num[t], Num[a], z1,z2);
			a = par[t][0];
		}
	}
	return res;
}
string GetString(int a, int pp, int L) {
	a = Up(a, max(Dep[a] - Dep[pp] - L, 0));
	string t = "";
	L = Dep[a] - Dep[pp];
	if (!L)return t;
	t.resize(L);
	int c = 0;
	while (a != pp) {
		t[c++] = pL[a] + 'a';
		a = par[a][0];
	}
	return t;
}
int oto[220];
int KMP(int LL) {
	int i, res = 0;
	oto[0] = -1;
	for (i = 0; i < m; i++) {
		int t = oto[i];
		while (t != -1 && w[i] != w[t])t = oto[t];
		oto[i + 1] = t + 1;
	}
	int pv = 0;
	for (i = 0; i < LL; i++) {
		while (pv != -1 && w[pv] != q[i])pv = oto[pv];
		pv++;
		if (pv == m)res++;
	}
	return res;
}
int main() {
	int i, a, b, j;
	char pp[3];
	po[0][0]=po[0][1] = 1;
	for (i = 1; i <= 100000; i++)for(j=0;j<2;j++)po[i][j] = po[i - 1][j] * BS % Mod[j];
	scanf("%d", &n);
	for (i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		scanf("%s", pp);
		E[a].push_back(b);
		E[b].push_back(a);
		L[a].push_back(pp[0] - 'a');
		L[b].push_back(pp[0] - 'a');
	}
	DFS(1, 0);
	HLD(1, 1);
	for (i = 1; i <= n; i++) {
		int x = i;
		long long s1 = 0, s2 = 0;
		for (j = 0; j < min(100, Dep[i]); j++) {
			s1 = (s2 * BS + pL[x]) % Mod[0];
			s2 = (s2 * BS + pL[x]) % Mod[1];
			x = par[x][0];
			V[j + 1].push_back({ {s1,s2},Num[i] });
		}
	}
	for (i = 1; i <= 100; i++)if (!V[i].empty())sort(V[i].begin(), V[i].end());
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d", &a, &b);
		scanf("%s", p);
		long long s1[2] = { 0,0 }, s2[2] = { 0,0 };
		for (i = 0; p[i]; i++)w[i] = p[i] - 'a';
		m = i;
		for (i = 0; p[i]; i++) {
			for (j = 0; j < 2; j++) {
				s1[j] = (s1[j] + w[i] * po[i][j]) % Mod[j];
				s2[j] = (s2[j] * BS + w[i]) % Mod[j];
			}
		}
		int l = LCA(a, b);
		int res = Go(a, l, s2[0],s2[1]);
		res += Go(b, l, s1[0],s1[1]);

		string t1 = GetString(a, l, m - 1);
		string t2 = GetString(b, l, m - 1);
		int c = 0;
		for (i = 0; i < t1.size(); i++)q[c++] = t1[i] - 'a';
		for (i = t2.size()-1; i >= 0; i--)q[c++] = t2[i] - 'a';
		res += KMP(c);
		printf("%d\n", res);
	}

}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#define pii pair<int,int>
#define N_ 101000
using namespace std;
vector<int>E[N_], L[N_];
vector<pii>V[110];
int pL[N_], n, D[N_][110], D2[N_][110], Dep[N_], par[N_][20], Num[N_], cnt, Ed[N_], C[N_], PPP[N_], ReNum[N_];
long long BS = 26, Mod = 1000000007, po[N_];
void DFS(int a, int pp) {
	int i;
	C[a]++;
	par[a][0] = pp;
	for (i = 0; i < 18; i++)par[a][i+1] = par[par[a][i]][i];
	for (i = 0; i < E[a].size();i++) {
		int x = E[a][i];
		if (x == pp)continue;
		Dep[x] = Dep[a] + 1;
		pL[x] = L[a][i];
		DFS(x, a);
		C[a] += C[x];
	}
}
int Up(int a, int d) {
	int i = 0;
	while (d) {
		if (d & 1)a = par[a][i];
		i++; d >>= 1;
	}
	return a;
}
void HLD(int a, int ppp) {
	PPP[a] = ppp;
	Num[a] = ++cnt;
	ReNum[cnt] = a;
	int Mx = -1, pv = -1;
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (Mx < C[x])Mx = C[x], pv = x;
	}
	if (pv == -1) {
		Ed[a] = cnt;
		return;
	}
	HLD(pv, ppp);
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (x != pv)HLD(x, x);
	}
	Ed[a] = cnt;
}
int LCA(int a, int b) {
	if (Dep[a] < Dep[b])return LCA(b, a);
	a = Up(a, Dep[a] - Dep[b]);
	int i;
	for (i = 17; i >= 0; i--)if (par[a][i] != par[b][i])a = par[a][i], b = par[b][i];
	if (a != b)a = par[a][0];
	return a;
}
char p[110];
int m, w[110], q[220];
int Get(int b, int e, int z) {
	return lower_bound(V[m].begin(), V[m].end(), pii(z,e+1)) - lower_bound(V[m].begin(), V[m].end(), pii(z,b));
}
int Go(int a, int pp, int z) {
	int i;
	int l = Dep[a] - Dep[pp];
	if (l < m)return 0;
	int rp = Up(a, l - m), res = 0;
	while (1) {
		int t = PPP[a];
		if (Dep[t] <= Dep[rp]) {
			res += Get(Num[rp], Num[a], z);
			break;
		}
		else {
			res += Get(Num[t], Num[a], z);
			a = par[t][0];
		}
	}
	return res;
}
string GetString(int a, int pp, int L) {
	a = Up(a, max(Dep[a] - Dep[pp] - L, 0));
	string t = "";
	L = Dep[a] - Dep[pp];
	if (!L)return t;
	t.resize(L);
	int c = 0;
	while (a != pp) {
		t[c++] = pL[a] + 'a';
		a = par[a][0];
	}
	return t;
}
int oto[220];
int KMP(int LL) {
	int i, res = 0;
	oto[0] = -1;
	for (i = 0; i < m; i++) {
		int t = oto[i];
		while (t != -1 && w[i] != w[t])t = oto[t];
		oto[i + 1] = t + 1;
	}
	int pv = 0;
	for (i = 0; i < LL; i++) {
		while (pv != -1 && w[pv] != q[i])pv = oto[pv];
		pv++;
		if (pv == m)res++;
	}
	return res;
}
int main() {
	int i, a, b, j;
	char pp[3];
	po[0] = 1;
	for (i = 1; i <= 100000; i++)po[i] = po[i - 1] * BS % Mod;
	scanf("%d", &n);
	for (i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		scanf("%s", pp);
		E[a].push_back(b);
		E[b].push_back(a);
		L[a].push_back(pp[0] - 'a');
		L[b].push_back(pp[0] - 'a');
	}
	DFS(1, 0);
	HLD(1, 1);
	for (i = 1; i <= n; i++) {
		int x = i;
		long long s1 = 0, s2 = 0;
		for (j = 0; j < min(100, Dep[i]); j++) {
			s2 = (s2 * BS + pL[x]) % Mod;
			x = par[x][0];
			D[i][j + 1] = s2;
			V[j + 1].push_back({ s2,Num[i] });
		}
	}
	for (i = 1; i <= 100; i++)if (!V[i].empty())sort(V[i].begin(), V[i].end());
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d", &a, &b);
		scanf("%s", p);
		long long s1 = 0, s2 = 0;
		for (i = 0; p[i]; i++)w[i] = p[i] - 'a';
		m = i;
		for (i = 0; p[i]; i++) {
			s1 = (s1 + w[i] * po[i]) % Mod;
			s2 = (s2 * BS + w[i]) % Mod;
		}
		int l = LCA(a, b);
		int res = Go(a, l, s2);
		res += Go(b, l, s1);

		string t1 = GetString(a, l, m - 1);
		string t2 = GetString(b, l, m - 1);
		int c = 0;
		for (i = 0; i < t1.size(); i++)q[c++] = t1[i] - 'a';
		for (i = t2.size()-1; i >= 0; i--)q[c++] = t2[i] - 'a';
		res += KMP(c);
		printf("%d\n", res);
	}

}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#define pii pair<int,int>
#define N_ 101000
using namespace std;
vector<int>E[N_], L[N_];
vector<pii>V[110];
int pL[N_], n, D[N_][110], D2[N_][110], Dep[N_], par[N_][20], Num[N_], cnt, Ed[N_], C[N_], PPP[N_], ReNum[N_];
long long BS = 29, Mod = 1000000007, po[N_];
void DFS(int a, int pp) {
	int i;
	C[a]++;
	par[a][0] = pp;
	for (i = 0; i < 18; i++)par[a][i+1] = par[par[a][i]][i];
	for (i = 0; i < E[a].size();i++) {
		int x = E[a][i];
		if (x == pp)continue;
		Dep[x] = Dep[a] + 1;
		pL[x] = L[a][i];
		DFS(x, a);
		C[a] += C[x];
	}
}
int Up(int a, int d) {
	int i = 0;
	while (d) {
		if (d & 1)a = par[a][i];
		i++; d >>= 1;
	}
	return a;
}
void HLD(int a, int ppp) {
	PPP[a] = ppp;
	Num[a] = ++cnt;
	ReNum[cnt] = a;
	int Mx = -1, pv = -1;
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (Mx < C[x])Mx = C[x], pv = x;
	}
	if (pv == -1) {
		Ed[a] = cnt;
		return;
	}
	HLD(pv, ppp);
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (x != pv)HLD(x, x);
	}
	Ed[a] = cnt;
}
int LCA(int a, int b) {
	if (Dep[a] < Dep[b])return LCA(b, a);
	a = Up(a, Dep[a] - Dep[b]);
	int i;
	for (i = 17; i >= 0; i--)if (par[a][i] != par[b][i])a = par[a][i], b = par[b][i];
	if (a != b)a = par[a][0];
	return a;
}
char p[110];
int m, w[110], q[220];
int Get(int b, int e, int z) {
	return lower_bound(V[m].begin(), V[m].end(), pii(z,e+1)) - lower_bound(V[m].begin(), V[m].end(), pii(z,b));
}
int Go(int a, int pp, int z) {
	int i;
	int l = Dep[a] - Dep[pp];
	if (l < m)return 0;
	int rp = Up(a, l - m), res = 0;
	while (1) {
		int t = PPP[a];
		if (Dep[t] <= Dep[rp]) {
			res += Get(Num[rp], Num[a], z);
			break;
		}
		else {
			res += Get(Num[t], Num[a], z);
			a = par[t][0];
		}
	}
	return res;
}
string GetString(int a, int pp, int L) {
	a = Up(a, max(Dep[a] - Dep[pp] - L, 0));
	string t = "";
	L = Dep[a] - Dep[pp];
	if (!L)return t;
	t.resize(L);
	int c = 0;
	while (a != pp) {
		t[c++] = pL[a] + 'a';
		a = par[a][0];
	}
	return t;
}
int oto[220];
int KMP(int LL) {
	int i, res = 0;
	oto[0] = -1;
	for (i = 0; i < m; i++) {
		int t = oto[i];
		while (t != -1 && w[i] != w[t])t = oto[t];
		oto[i + 1] = t + 1;
	}
	int pv = 0;
	for (i = 0; i < LL; i++) {
		while (pv != -1 && w[pv] != q[i])pv = oto[pv];
		pv++;
		if (pv == m)res++;
	}
	return res;
}
int main() {
	int i, a, b, j;
	char pp[3];
	po[0] = 1;
	for (i = 1; i <= 100000; i++)po[i] = po[i - 1] * BS % Mod;
	scanf("%d", &n);
	for (i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		scanf("%s", pp);
		E[a].push_back(b);
		E[b].push_back(a);
		L[a].push_back(pp[0] - 'a');
		L[b].push_back(pp[0] - 'a');
	}
	DFS(1, 0);
	HLD(1, 1);
	for (i = 1; i <= n; i++) {
		int x = i;
		long long s1 = 0, s2 = 0;
		for (j = 0; j < min(100, Dep[i]); j++) {
			s2 = (s2 * BS + pL[x]) % Mod;
			x = par[x][0];
			D[i][j + 1] = s2;
			V[j + 1].push_back({ s2,Num[i] });
		}
	}
	for (i = 1; i <= 100; i++)if (!V[i].empty())sort(V[i].begin(), V[i].end());
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d", &a, &b);
		scanf("%s", p);
		long long s1 = 0, s2 = 0;
		for (i = 0; p[i]; i++)w[i] = p[i] - 'a';
		m = i;
		for (i = 0; p[i]; i++) {
			s1 = (s1 + w[i] * po[i]) % Mod;
			s2 = (s2 * BS + w[i]) % Mod;
		}
		int l = LCA(a, b);
		int res = Go(a, l, s2);
		res += Go(b, l, s1);

		string t1 = GetString(a, l, m - 1);
		string t2 = GetString(b, l, m - 1);
		int c = 0;
		for (i = 0; i < t1.size(); i++)q[c++] = t1[i] - 'a';
		for (i = t2.size()-1; i >= 0; i--)q[c++] = t2[i] - 'a';
		res += KMP(c);
		printf("%d\n", res);
	}

}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#define pii pair<int,int>
#define piii pair< pii,int>
#define N_ 101000
using namespace std;
vector<int>E[N_], L[N_];
vector<piii>V[110];
int pL[N_], n, Dep[N_], par[N_][20], Num[N_], cnt, C[N_], PPP[N_], ReNum[N_];
long long BS = 26, Mod[2] = { 1000000007,1000000009 }, po[N_][2];
void DFS(int a, int pp) {
	int i;
	C[a]++;
	par[a][0] = pp;
	for (i = 0; i < 18; i++)par[a][i+1] = par[par[a][i]][i];
	for (i = 0; i < E[a].size();i++) {
		int x = E[a][i];
		if (x == pp)continue;
		Dep[x] = Dep[a] + 1;
		pL[x] = L[a][i];
		DFS(x, a);
		C[a] += C[x];
	}
}
int Up(int a, int d) {
	int i = 0;
	while (d) {
		if (d & 1)a = par[a][i];
		i++; d >>= 1;
	}
	return a;
}
void HLD(int a, int ppp) {
	PPP[a] = ppp;
	Num[a] = ++cnt;
	ReNum[cnt] = a;
	int Mx = -1, pv = -1;
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (Mx < C[x])Mx = C[x], pv = x;
	}
	if (pv == -1) {
		return;
	}
	HLD(pv, ppp);
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (x != pv)HLD(x, x);
	}
}
int LCA(int a, int b) {
	if (Dep[a] < Dep[b])return LCA(b, a);
	a = Up(a, Dep[a] - Dep[b]);
	int i;
	for (i = 17; i >= 0; i--)if (par[a][i] != par[b][i])a = par[a][i], b = par[b][i];
	if (a != b)a = par[a][0];
	return a;
}
char p[110];
int m, w[110], q[220];
int Get(int b, int e, int z1, int z2) {
	return lower_bound(V[m].begin(), V[m].end(), piii(pii(z1,z2),e+1)) - lower_bound(V[m].begin(), V[m].end(), piii(pii(z1, z2),b));
}
int Go(int a, int pp, int z1, int z2) {
	int i;
	int l = Dep[a] - Dep[pp];
	if (l < m)return 0;
	int rp = Up(a, l - m), res = 0;
	while (1) {
		int t = PPP[a];
		if (Dep[t] <= Dep[rp]) {
			res += Get(Num[rp], Num[a], z1,z2);
			break;
		}
		else {
			res += Get(Num[t], Num[a], z1,z2);
			a = par[t][0];
		}
	}
	return res;
}
string GetString(int a, int pp, int L) {
	a = Up(a, max(Dep[a] - Dep[pp] - L, 0));
	string t = "";
	L = Dep[a] - Dep[pp];
	if (!L)return t;
	t.resize(L);
	int c = 0;
	while (a != pp) {
		t[c++] = pL[a] + 'a';
		a = par[a][0];
	}
	return t;
}
int oto[220];
int KMP(int LL) {
	int i, res = 0;
	oto[0] = -1;
	for (i = 0; i < m; i++) {
		int t = oto[i];
		while (t != -1 && w[i] != w[t])t = oto[t];
		oto[i + 1] = t + 1;
	}
	int pv = 0;
	for (i = 0; i < LL; i++) {
		while (pv != -1 && w[pv] != q[i])pv = oto[pv];
		pv++;
		if (pv == m)res++;
	}
	return res;
}
int main() {
	int i, a, b, j;
	char pp[3];
	po[0][0]=po[0][1] = 1;
	for (i = 1; i <= 100000; i++)for(j=0;j<2;j++)po[i][j] = po[i - 1][j] * BS % Mod[j];
	scanf("%d", &n);
	for (i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		scanf("%s", pp);
		E[a].push_back(b);
		E[b].push_back(a);
		L[a].push_back(pp[0] - 'a');
		L[b].push_back(pp[0] - 'a');
	}
	DFS(1, 0);
	HLD(1, 1);
	for (i = 1; i <= n; i++) {
		int x = i;
		long long s1 = 0, s2 = 0;
		for (j = 0; j < min(100, Dep[i]); j++) {
			s1 = (s1 * BS + pL[x]) % Mod[0];
			s2 = (s2 * BS + pL[x]) % Mod[1];
			x = par[x][0];
			V[j + 1].push_back({ {s1,s2},Num[i] });
		}
	}
	for (i = 1; i <= 100; i++)if (!V[i].empty())sort(V[i].begin(), V[i].end());
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d", &a, &b);
		scanf("%s", p);
		long long s1[2] = { 0,0 }, s2[2] = { 0,0 };
		for (i = 0; p[i]; i++)w[i] = p[i] - 'a';
		m = i;
		for (i = 0; p[i]; i++) {
			for (j = 0; j < 2; j++) {
				s1[j] = (s1[j] + w[i] * po[i][j]) % Mod[j];
				s2[j] = (s2[j] * BS + w[i]) % Mod[j];
			}
		}
		int l = LCA(a, b);
		int res = Go(a, l, s2[0],s2[1]);
		res += Go(b, l, s1[0],s1[1]);

		string t1 = GetString(a, l, m - 1);
		string t2 = GetString(b, l, m - 1);
		int c = 0;
		for (i = 0; i < t1.size(); i++)q[c++] = t1[i] - 'a';
		for (i = t2.size()-1; i >= 0; i--)q[c++] = t2[i] - 'a';
		res += KMP(c);
		printf("%d\n", res);
	}

}


#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#define pii pair<int,int>
#define piii pair< pii,int>
#define N_ 101000
using namespace std;
vector<int>E[N_], L[N_];
vector<piii>V[110];
int pL[N_], n, Dep[N_], par[N_][20], Num[N_], cnt, C[N_], PPP[N_], ReNum[N_];
long long BS = 26, Mod[2] = { 1000000007,1392148321 }, po[N_][2];
void DFS(int a, int pp) {
	int i;
	C[a]++;
	par[a][0] = pp;
	for (i = 0; i < 18; i++)par[a][i+1] = par[par[a][i]][i];
	for (i = 0; i < E[a].size();i++) {
		int x = E[a][i];
		if (x == pp)continue;
		Dep[x] = Dep[a] + 1;
		pL[x] = L[a][i];
		DFS(x, a);
		C[a] += C[x];
	}
}
int Up(int a, int d) {
	int i = 0;
	while (d) {
		if (d & 1)a = par[a][i];
		i++; d >>= 1;
	}
	return a;
}
void HLD(int a, int ppp) {
	PPP[a] = ppp;
	Num[a] = ++cnt;
	ReNum[cnt] = a;
	int Mx = -1, pv = -1;
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (Mx < C[x])Mx = C[x], pv = x;
	}
	if (pv == -1) {
		return;
	}
	HLD(pv, ppp);
	for (auto &x : E[a]) {
		if (x == par[a][0])continue;
		if (x != pv)HLD(x, x);
	}
}
int LCA(int a, int b) {
	if (Dep[a] < Dep[b])return LCA(b, a);
	a = Up(a, Dep[a] - Dep[b]);
	int i;
	for (i = 17; i >= 0; i--)if (par[a][i] != par[b][i])a = par[a][i], b = par[b][i];
	if (a != b)a = par[a][0];
	return a;
}
char p[110];
int m, w[110], q[220];
int Get(int b, int e, int z1, int z2) {
	return lower_bound(V[m].begin(), V[m].end(), piii(pii(z1,z2),e+1)) - lower_bound(V[m].begin(), V[m].end(), piii(pii(z1, z2),b));
}
int Go(int a, int pp, int z1, int z2) {
	int i;
	int l = Dep[a] - Dep[pp];
	if (l < m)return 0;
	int rp = Up(a, l - m), res = 0;
	while (1) {
		int t = PPP[a];
		if (Dep[t] <= Dep[rp]) {
			res += Get(Num[rp], Num[a], z1,z2);
			break;
		}
		else {
			res += Get(Num[t], Num[a], z1,z2);
			a = par[t][0];
		}
	}
	return res;
}
string GetString(int a, int pp, int L) {
	a = Up(a, max(Dep[a] - Dep[pp] - L, 0));
	string t = "";
	L = Dep[a] - Dep[pp];
	if (!L)return t;
	t.resize(L);
	int c = 0;
	while (a != pp) {
		t[c++] = pL[a] + 'a';
		a = par[a][0];
	}
	return t;
}
int oto[220];
int KMP(int LL) {
	int i, res = 0;
	oto[0] = -1;
	for (i = 0; i < m; i++) {
		int t = oto[i];
		while (t != -1 && w[i] != w[t])t = oto[t];
		oto[i + 1] = t + 1;
	}
	int pv = 0;
	for (i = 0; i < LL; i++) {
		while (pv != -1 && w[pv] != q[i])pv = oto[pv];
		pv++;
		if (pv == m)res++;
	}
	return res;
}
int main() {
	int i, a, b, j;
	char pp[3];
	po[0][0]=po[0][1] = 1;
	for (i = 1; i <= 100000; i++)for(j=0;j<2;j++)po[i][j] = po[i - 1][j] * BS % Mod[j];
	scanf("%d", &n);
	for (i = 1; i < n; i++) {
		scanf("%d%d", &a, &b);
		scanf("%s", pp);
		E[a].push_back(b);
		E[b].push_back(a);
		L[a].push_back(pp[0] - 'a');
		L[b].push_back(pp[0] - 'a');
	}
	DFS(1, 0);
	HLD(1, 1);
	for (i = 1; i <= n; i++) {
		int x = i;
		long long s1 = 0, s2 = 0;
		for (j = 0; j < min(100, Dep[i]); j++) {
			s1 = (s2 * BS + pL[x]) % Mod[0];
			s2 = (s2 * BS + pL[x]) % Mod[1];
			x = par[x][0];
			V[j + 1].push_back({ {s1,s2},Num[i] });
		}
	}
	for (i = 1; i <= 100; i++)if (!V[i].empty())sort(V[i].begin(), V[i].end());
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		scanf("%d%d", &a, &b);
		scanf("%s", p);
		long long s1[2] = { 0,0 }, s2[2] = { 0,0 };
		for (i = 0; p[i]; i++)w[i] = p[i] - 'a';
		m = i;
		for (i = 0; p[i]; i++) {
			for (j = 0; j < 2; j++) {
				s1[j] = (s1[j] + w[i] * po[i][j]) % Mod[j];
				s2[j] = (s2[j] * BS + w[i]) % Mod[j];
			}
		}
		int l = LCA(a, b);
		int res = Go(a, l, s2[0],s2[1]);
		res += Go(b, l, s1[0],s1[1]);

		string t1 = GetString(a, l, m - 1);
		string t2 = GetString(b, l, m - 1);
		int c = 0;
		for (i = 0; i < t1.size(); i++)q[c++] = t1[i] - 'a';
		for (i = t2.size()-1; i >= 0; i--)q[c++] = t2[i] - 'a';
		res += KMP(c);
		printf("%d\n", res);
	}

}