#include <bits/stdc++.h>
using namespace std;
int n, m;
int rt[500005 << 1], P[500005], L[500005];
struct Node {
  int mx, id;
  Node() {}
  Node(int a, int b) { mx = a, id = b; }
  Node operator+(Node x) {
    if (id == x.id) return Node(mx + x.mx, id);
    if (mx > x.mx)
      return *this;
    else if (mx < x.mx)
      return x;
    else
      return Node(mx, min(id, x.id));
  }
};
struct Segment_Tree {
  int cnt;
  int ls[500005 * 20], rs[500005 * 20];
  Node val[500005 * 20];
  void update(int &pos, int l, int r, int p) {
    if (!pos) pos = ++cnt;
    if (l == r) return val[pos] = Node(1, l), void();
    int mid = (l + r) >> 1;
    if (mid >= p)
      update(ls[pos], l, mid, p);
    else
      update(rs[pos], mid + 1, r, p);
    val[pos] = val[ls[pos]] + val[rs[pos]];
    return;
  }
  int merge(int x, int y, int l, int r) {
    if (!x || !y) return x | y;
    if (l == r) {
      val[++cnt] = val[x] + val[y];
      return cnt;
    }
    int mid = (l + r) >> 1, pos = ++cnt;
    ls[pos] = merge(ls[x], ls[y], l, mid);
    rs[pos] = merge(rs[x], rs[y], mid + 1, r);
    val[pos] = val[ls[pos]] + val[rs[pos]];
    return pos;
  }
  Node query(int pos, int l, int r, int nl, int nr) {
    if (!pos || (l >= nl && r <= nr)) return val[pos];
    int mid = (l + r) >> 1;
    Node ans = Node(0, 0);
    if (mid >= nl) ans = ans + query(ls[pos], l, mid, nl, nr);
    if (mid < nr) ans = ans + query(rs[pos], mid + 1, r, nl, nr);
    return ans;
  }
} T;
struct SAM {
  int cnt, lst;
  int fail[500005], ch[500005][26], fa[500005][20], len[500005];
  vector<int> son[500005];
  void ins(int x, int id) {
    int np = ++cnt, p = lst;
    lst = np;
    len[np] = len[p] + 1;
    T.update(rt[np], 1, n, id);
    for (; p && !ch[p][x]; p = fail[p]) ch[p][x] = np;
    if (!p)
      fail[np] = 1;
    else {
      int q = ch[p][x];
      if (len[q] == len[p] + 1)
        fail[np] = q;
      else {
        int nq = ++cnt;
        memcpy(ch[nq], ch[q], sizeof ch[nq]);
        fail[nq] = fail[q];
        len[nq] = len[p] + 1;
        fail[np] = fail[q] = nq;
        for (; p && ch[p][x] == q; p = fail[p]) ch[p][x] = nq;
      }
    }
    return;
  }
  void dfs(int u) {
    for (int i = 1; i <= 16; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    int sz = son[u].size();
    for (int i = sz - 1; ~i; --i) {
      int v = son[u][i];
      dfs(v);
      rt[u] = T.merge(rt[u], rt[v], 1, n);
    }
    return;
  }
  void build() {
    for (int i = 2; i <= cnt; ++i)
      son[fail[i]].push_back(i), fa[i][0] = fail[i];
    dfs(1);
    return;
  }
  void find(char *s) {
    int lens = strlen(s + 1), now = 1, l = 0;
    for (int i = 1; i <= lens; ++i) {
      int x = s[i] - 'a';
      if (ch[now][x])
        ++l, now = ch[now][x];
      else {
        while (now && !ch[now][x]) now = fail[now];
        if (!now)
          now = 1, l = 0;
        else
          l = len[now] + 1, now = ch[now][x];
      }
      P[i] = now;
      L[i] = l;
    }
    return;
  }
  Node query(int pl, int pr, int l, int r) {
    int now = P[pr], y = pr - pl + 1;
    for (int i = 16; ~i; --i)
      if (len[fa[now][i]] >= y) now = fa[now][i];
    return T.query(rt[now], 1, n, l, r);
  }
} sam;
char s[500005], t[500005];
int main() {
  scanf("%s%d", s + 1, &n);
  T.val[0] = Node(0, 0);
  sam.cnt = 1;
  for (int i = 1; i <= n; ++i) {
    scanf("%s", t + 1);
    int lent = strlen(t + 1);
    sam.lst = 1;
    for (int j = 1; j <= lent; ++j) sam.ins(t[j] - 'a', i);
  }
  sam.build();
  sam.find(s);
  scanf("%d", &m);
  while (m--) {
    int pl, pr, l, r;
    scanf("%d%d%d%d", &l, &r, &pl, &pr);
    if (L[pr] < pr - pl + 1) {
      printf("%d 0\n", l);
      continue;
    }
    Node tmp = sam.query(pl, pr, l, r);
    if (!tmp.mx) tmp.id = l;
    printf("%d %d\n", tmp.id, tmp.mx);
  }
  return 0;
}
