Problem: Misha has a tree with characters written on the vertices. He can choose two vertices s and t of this tree and write down characters of vertices lying on a path from s to t. We'll say that such string corresponds to pair (s, t).

Misha has m queries of type: you are given 4 vertices a, b, c, d; you need to find the largest common prefix of the strings that correspond to pairs (a, b) and (c, d). Your task is to help him.

Input

The first line contains integer n (1 ≤ n ≤ 300 000) — the number of vertices in the tree.

Next follows a line consisting of n small English letters. The i-th character of the string corresponds to the character written on the i-th vertex. 

Next n - 1 lines contain information about edges. An edge is defined by a pair of integers u, v (1 ≤ u, v ≤ n, u ≠ v), separated by spaces.

The next line contains integer m (1 ≤ m ≤ 1 000 000) — the number of queries.

Next m lines contain information about queries. A query is defined by four integers a, b, c, d (1 ≤ a, b, c, d ≤ n), separated by spaces.

Output

For each query print the length of the largest common prefix on a separate line.

Examples

Input

6
bbbabb
2 1
3 2
4 3
5 2
6 5
6
2 5 3 1
1 5 2 3
5 6 5 6
6 3 4 1
6 2 3 4
2 2 4 5


Output

2
2
2
0
1
0

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300000 + 10, maxq = 1000000 + 10;
const long long X = 123LL;
long long xpow[maxn], ixpow[maxn];
int getint() {
  char c = getchar();
  while (c < '0' || c > '9') c = getchar();
  int ret = 0;
  while (1) {
    ret = ret * 10 + c - '0';
    c = getchar();
    if (c < '0' || c > '9') return ret;
  }
}
char cc[12];
void printint(int x) {
  int cnt = 0;
  while (x) cc[cnt++] = '0' + x % 10, x /= 10;
  if (!cnt) cc[cnt++] = '0';
  for (int i = cnt - 1; i >= 0; i--) putchar(cc[i]);
  putchar('\n');
}
long long pow(long long x, int n) {
  if (n <= 1) return n ? x : 1LL;
  long long tmp = pow(x, n / 2);
  if (n & 1) return (tmp * tmp % 1000000007) * x % 1000000007;
  return tmp * tmp % 1000000007;
}
long long inv(long long x) { return pow(x, 1000000007 - 2); }
int bs[maxn];
int getbs(int x) { return x == bs[x] ? x : bs[x] = getbs(bs[x]); }
vector<int> v[maxn];
int n, fa[maxn], dep[maxn];
char s[maxn];
long long h1[maxn], h2[maxn];
void dfs(int x, int f, int d = 0) {
  dep[x] = d;
  fa[x] = f;
  if (x)
    h1[x] = (h1[f] * X + s[x] - 'a') % 1000000007,
    h2[x] = (h2[f] + xpow[d] * (s[x] - 'a')) % 1000000007;
  for (auto i : v[x])
    if (i != f) dfs(i, x, d + 1);
}
struct P {
  int val, id;
  P(int _v, int _i) { val = _v, id = _i; }
};
vector<P> v2[maxn];
int ansval[2 * maxq];
bool vis[maxn];
void dfs_solve_lca(int x, int f) {
  vis[x] = 1;
  for (auto i : v2[x])
    if (vis[i.val]) ansval[i.id] = getbs(i.val);
  v2[x].clear();
  for (auto i : v[x])
    if (i != f) dfs_solve_lca(i, x), bs[getbs(i)] = x;
}
int sta[maxn], top = 0;
void dfs_solve_fa(int x, int f) {
  sta[top++] = x;
  for (auto i : v2[x]) ansval[i.id] = sta[top - 1 - i.val];
  v2[x].clear();
  for (auto i : v[x])
    if (i != f) dfs_solve_fa(i, x);
  top--;
}
struct query {
  int x1, y1, x2, y2, lca1, lca2, l, r;
  void get(int qid) {
    x1 = getint(), y1 = getint();
    x2 = getint(), y2 = getint();
    v2[x1].emplace_back(y1, 2 * qid - 1);
    v2[y1].emplace_back(x1, 2 * qid - 1);
    v2[x2].emplace_back(y2, 2 * qid);
    v2[y2].emplace_back(x2, 2 * qid);
  }
  void get2(int qid) {
    if (s[x1] != s[x2]) {
      l = 0, r = 1;
      return;
    }
    lca1 = ansval[2 * qid - 1];
    lca2 = ansval[2 * qid];
    l = 1;
    r = min(dep[x1] + dep[y1] - 2 * dep[lca1],
            dep[x2] + dep[y2] - 2 * dep[lca2]) +
        2;
  }
} q[maxq];
int Qnum;
void precal_query() {
  dfs_solve_lca(0, 0);
  for (int i = 1; i <= Qnum; i++) q[i].get2(i);
}
long long gethash(int x, int y, int lca, int len, int query_pos) {
  long long ret;
  if (dep[x] - dep[lca] + 1 >= len)
    ret = h1[x] - h1[query_pos] * xpow[len];
  else {
    y = query_pos;
    int a = dep[x] - dep[lca];
    ret = h1[x] - h1[fa[lca]] * xpow[a + 1];
    int b = a + dep[y] - dep[lca];
    long long add = h2[y] - h2[fa[lca]];
    if (b > dep[y])
      add *= xpow[b - dep[y]];
    else if (b < dep[y])
      add *= ixpow[dep[y] - b];
    ret += add - (s[lca] - 'a') * xpow[a];
  }
  ret %= 1000000007;
  if (ret < 0) ret += 1000000007;
  return ret;
}
bool process_query() {
  bool ok = 1;
  for (int i = 1; i <= Qnum; i++)
    if (q[i].l + 1 != q[i].r) {
      ok = 0;
      int len = (q[i].l + q[i].r) >> 1;
      int x1 = q[i].x1, y1 = q[i].y1, lca1 = q[i].lca1;
      int x2 = q[i].x2, y2 = q[i].y2, lca2 = q[i].lca2;
      if (dep[x1] - dep[lca1] + 1 >= len)
        v2[x1].emplace_back(len, 2 * i - 1);
      else
        v2[y1].emplace_back(dep[x1] + dep[y1] - 2 * dep[lca1] + 1 - len,
                            2 * i - 1);
      if (dep[x2] - dep[lca2] + 1 >= len)
        v2[x2].emplace_back(len, 2 * i);
      else
        v2[y2].emplace_back(dep[x2] + dep[y2] - 2 * dep[lca2] + 1 - len, 2 * i);
    }
  if (ok) return 1;
  dfs_solve_fa(0, 0);
  for (int i = 1; i <= Qnum; i++)
    if (q[i].l + 1 != q[i].r) {
      int mid = (q[i].l + q[i].r) >> 1;
      if (gethash(q[i].x1, q[i].y1, q[i].lca1, mid, ansval[2 * i - 1]) ==
          gethash(q[i].x2, q[i].y2, q[i].lca2, mid, ansval[2 * i]))
        q[i].l = mid;
      else
        q[i].r = mid;
    }
  return 0;
}
int main() {
  if (fopen("in", "r")) {
    freopen("in", "r", stdin);
    freopen("out", "w", stdout);
  }
  n = getint();
  for (int i = 1; i <= n; i++) s[i] = getchar();
  long long IX = inv(X);
  for (int i = 0; i <= n; i++) {
    xpow[i] = i ? xpow[i - 1] * X % 1000000007 : 1LL;
    ixpow[i] = i ? ixpow[i - 1] * IX % 1000000007 : 1LL;
    bs[i] = i;
  }
  for (int i = 1; i < n; i++) {
    int x = getint(), y = getint();
    v[x].emplace_back(y);
    v[y].emplace_back(x);
  }
  v[0].push_back(1);
  dfs(0, 0, 0);
  Qnum = getint();
  for (int i = 1; i <= Qnum; i++) q[i].get(i);
  precal_query();
  while (!process_query())
    ;
  for (int i = 1; i <= Qnum; i++) printint(q[i].l);
}