#include <bits/stdc++.h>
using namespace std;
const int inf = ~0U >> 2;
const long long infl = ~0LLU >> 2;
template <class T>
inline void Min(T &x, T y) {
  if (y < x) x = y;
}
template <class T>
inline void Max(T &x, T y) {
  if (y > x) x = y;
}
const int mod = 1e9 + 7;
inline int Add(int x) { return x >= mod ? x - mod : x; }
inline void Add(int &x, int y) {
  x += y;
  if (x >= mod) x -= mod;
}
inline int Sub(int x) { return x < 0 ? x + mod : x; }
inline void Sub(int &x, int y) {
  x -= y;
  if (x < 0) x += mod;
}
inline int Mul(int x, int y) { return (int)((long long)x * y % mod); }
inline int Mul(int x, int y, int z) { return Mul(x, Mul(y, z)); }
int Pow(int x, int y) {
  int z = 1;
  for (; y; y >>= 1) {
    if (y & 1) z = Mul(z, x);
    x = Mul(x, x);
  }
  return z;
}
int Inv(int x) { return Pow(x, mod - 2); }
const int maxn = 3e5;
int n;
vector<int> g[maxn];
char ch[maxn + 1];
int dep[maxn], par[maxn], size[maxn], son[maxn], top[maxn];
int dfn[maxn], clk, ord[maxn];
void Dfs1(int u) {
  son[u] = -1;
  size[u] = 1;
  for (int v : g[u]) {
    if (v == par[u]) continue;
    par[v] = u;
    dep[v] = dep[u] + 1;
    Dfs1(v);
    size[u] += size[v];
    if (son[u] == -1 || size[v] > size[son[u]]) son[u] = v;
  }
}
void Dfs2(int u) {
  dfn[u] = clk;
  ord[clk++] = u;
  if (son[u] != -1) {
    top[son[u]] = top[u];
    Dfs2(son[u]);
  }
  for (int v : g[u]) {
    if (v == par[u] || v == son[u]) continue;
    top[v] = v;
    Dfs2(v);
  }
}
void InitTree(void) {
  clk = 0;
  par[0] = -1;
  dep[0] = 0;
  Dfs1(0);
  top[0] = 0;
  Dfs2(0);
}
const int base1 = 10037, base2 = 1000037;
char str[maxn];
int pow1[maxn + 1], pow2[maxn + 1];
int pre1[maxn + 1], pre2[maxn + 1];
int suf1[maxn + 1], suf2[maxn + 1];
void InitHash(void) {
  for (int i = 0; i < n; ++i) {
    str[i] = ch[ord[i]];
  }
  pow1[0] = pow2[0] = 1;
  pre1[0] = pre2[0] = 0;
  for (int i = 0; i < n; ++i) {
    pow1[i + 1] = Mul(pow1[i], base1);
    pow2[i + 1] = Mul(pow2[i], base2);
    pre1[i + 1] = Add(Mul(pre1[i], base1) + str[i] - 'a');
    pre2[i + 1] = Add(Mul(pre2[i], base2) + str[i] - 'a');
  }
  suf1[n] = suf2[n] = 0;
  for (int i = n - 1; i >= 0; --i) {
    suf1[i] = Add(Mul(suf1[i + 1], base1) + str[i] - 'a');
    suf2[i] = Add(Mul(suf2[i + 1], base2) + str[i] - 'a');
  }
}
unsigned long long GetHash(int l, int r) {
  int hash1 = Sub(pre1[r] - Mul(pre1[l], pow1[r - l]));
  int hash2 = Sub(pre2[r] - Mul(pre2[l], pow2[r - l]));
  return (unsigned long long)hash1 << 31 | hash2;
}
unsigned long long GetHashRev(int l, int r) {
  int hash1 = Sub(suf1[l] - Mul(suf1[r], pow1[r - l]));
  int hash2 = Sub(suf2[l] - Mul(suf2[r], pow2[r - l]));
  return (unsigned long long)hash1 << 31 | hash2;
}
struct Interval {
  int s, t;
  int Len(void) const { return abs(s - t) + 1; }
  Interval Pre(int len) const {
    if (s <= t) {
      return {s, s + len - 1};
    } else {
      return {s, s - len + 1};
    }
  }
  void Cut(int len) {
    if (s <= t) {
      s += len;
    } else {
      s -= len;
    }
  }
  unsigned long long Hash(void) const {
    if (s <= t) {
      return GetHash(s, t + 1);
    } else {
      return GetHashRev(t, s + 1);
    }
  }
};
vector<Interval> GetPath(int s, int t) {
  vector<Interval> ans1, ans2;
  while (top[s] != top[t]) {
    if (dep[top[s]] > dep[top[t]]) {
      ans1.push_back({dfn[s], dfn[top[s]]});
      s = par[top[s]];
    } else {
      ans2.push_back({dfn[top[t]], dfn[t]});
      t = par[top[t]];
    }
  }
  ans1.push_back({dfn[s], dfn[t]});
  copy(ans2.rbegin(), ans2.rend(), inserter(ans1, ans1.end()));
  return ans1;
}
int GetLcp(Interval a, Interval b) {
  int len = min(a.Len(), b.Len());
  int l = 0, r = len + 1;
  while (r - l > 1) {
    int mid = l + r >> 1;
    if (a.Pre(mid).Hash() == b.Pre(mid).Hash()) {
      l = mid;
    } else {
      r = mid;
    }
  }
  return l;
}
int GetLcp(vector<Interval> a, vector<Interval> b) {
  int na = (int)a.size(), nb = (int)b.size(), ans = 0;
  int i = 0, j = 0;
  while (i < na && j < nb) {
    int len = min(a[i].Len(), b[j].Len());
    if (a[i].Len() == b[j].Len()) {
      if (a[i].Hash() != b[j].Hash()) {
        return ans + GetLcp(a[i], b[j]);
      }
      ans += len;
      ++i;
      ++j;
    } else if (a[i].Len() < b[j].Len()) {
      if (a[i].Hash() != b[j].Pre(len).Hash()) {
        return ans + GetLcp(a[i], b[j]);
      }
      ans += len;
      ++i;
      b[j].Cut(len);
    } else {
      if (a[i].Pre(len).Hash() != b[j].Hash()) {
        return ans + GetLcp(a[i], b[j]);
      }
      ans += len;
      ++j;
      a[i].Cut(len);
    }
  }
  return ans;
}
int main(void) {
  scanf("%d", &n);
  scanf("%s", ch);
  for (int i = 0; i < n - 1; ++i) {
    int u, v;
    scanf("%d%d", &u, &v);
    --u;
    --v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  InitTree();
  InitHash();
  int m;
  scanf("%d", &m);
  for (int i = 0; i < m; ++i) {
    int a, b, c, d;
    scanf("%d%d%d%d", &a, &b, &c, &d);
    --a;
    --b;
    --c;
    --d;
    vector<Interval> path1, path2;
    path1 = GetPath(a, b);
    path2 = GetPath(c, d);
    int ans = GetLcp(path1, path2);
    printf("%d\n", ans);
  }
  return 0;
}
