package main
import (
"bufio"
"os"
"strconv"
)
const MAX_SEG_NODES = 8000005
const MAX_SAM_NODES = 200005
var ls [MAX_SEG_NODES]int32
var rs [MAX_SEG_NODES]int32
var maxVal [MAX_SEG_NODES]int32
var maxIdx [MAX_SEG_NODES]int32
var segNodes int32 = 0
func allocNode() int32 {
segNodes++
return segNodes
}
func pushUp(u int32) {
if maxVal[ls[u]] > maxVal[rs[u]] {
maxVal[u] = maxVal[ls[u]]
maxIdx[u] = maxIdx[ls[u]]
} else if maxVal[ls[u]] < maxVal[rs[u]] {
maxVal[u] = maxVal[rs[u]]
maxIdx[u] = maxIdx[rs[u]]
} else {
maxVal[u] = maxVal[ls[u]]
if maxIdx[ls[u]] <= maxIdx[rs[u]] {
maxIdx[u] = maxIdx[ls[u]]
} else {
maxIdx[u] = maxIdx[rs[u]]
}
}
}
func insert(u *int32, l, r, pos int32) {
if *u == 0 {
*u = allocNode()
}
if l == r {
maxVal[*u]++
maxIdx[*u] = l
return
}
mid := (l + r) / 2
if pos <= mid {
insert(&ls[*u], l, mid, pos)
} else {
insert(&rs[*u], mid+1, r, pos)
}
pushUp(*u)
}
func merge(u, v int32, l, r int32) int32 {
if u == 0 || v == 0 {
return u ^ v
}
newNode := allocNode()
if l == r {
maxVal[newNode] = maxVal[u] + maxVal[v]
maxIdx[newNode] = l
return newNode
}
mid := (l + r) / 2
ls[newNode] = merge(ls[u], ls[v], l, mid)
rs[newNode] = merge(rs[u], rs[v], mid+1, r)
pushUp(newNode)
return newNode
}
func querySeg(u int32, l, r, ql, qr int32) (int32, int32) {
if u == 0 {
return 0, 0
}
if ql <= l && r <= qr {
return maxVal[u], maxIdx[u]
}
mid := (l + r) / 2
var ansVal, ansIdx int32 = -1, -1
if ql <= mid {
v, idx := querySeg(ls[u], l, mid, ql, qr)
if v > ansVal || (v == ansVal && idx < ansIdx) {
ansVal, ansIdx = v, idx
}
}
if qr > mid {
v, idx := querySeg(rs[u], mid+1, r, ql, qr)
if v > ansVal || (v == ansVal && idx < ansIdx) {
ansVal, ansIdx = v, idx
}
}
return ansVal, ansIdx
}
var samNext [MAX_SAM_NODES][26]int32
var samLink [MAX_SAM_NODES]int32
var samLen [MAX_SAM_NODES]int32
var root [MAX_SAM_NODES]int32
var head [MAX_SAM_NODES]int32
var nxt [MAX_SAM_NODES]int32
var up [MAX_SAM_NODES][18]int32
var samNodes int32 = 0
func allocSamNode() int32 {
samNodes++
samLink[samNodes] = 0
return samNodes
}
func initSAM() {
allocSamNode()
}
func extend(c int32, last int32) int32 {
if samNext[last][c] != 0 {
q := samNext[last][c]
if samLen[q] == samLen[last]+1 {
return q
}
clone := allocSamNode()
samLen[clone] = samLen[last] + 1
for i := int32(0); i < 26; i++ {
samNext[clone][i] = samNext[q][i]
}
samLink[clone] = samLink[q]
samLink[q] = clone
for p := last; p != 0 && samNext[p][c] == q; p = samLink[p] {
samNext[p][c] = clone
}
return clone
}
cur := allocSamNode()
samLen[cur] = samLen[last] + 1
p := last
for p != 0 && samNext[p][c] == 0 {
samNext[p][c] = cur
p = samLink[p]
}
if p == 0 {
samLink[cur] = 1
} else {
q := samNext[p][c]
if samLen[q] == samLen[p]+1 {
samLink[cur] = q
} else {
clone := allocSamNode()
samLen[clone] = samLen[p] + 1
for i := int32(0); i < 26; i++ {
samNext[clone][i] = samNext[q][i]
}
samLink[clone] = samLink[q]
samLink[q] = clone
samLink[cur] = clone
for p != 0 && samNext[p][c] == q {
samNext[p][c] = clone
p = samLink[p]
}
}
}
return cur
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Buffer(make([]byte, 1024*1024), 10*1024*1024)
scanner.Split(bufio.ScanWords)
if !scanner.Scan() {
return
}
s := scanner.Text()
if !scanner.Scan() {
return
}
m, _ := strconv.Atoi(scanner.Text())
initSAM()
for i := 1; i <= m; i++ {
if !scanner.Scan() {
return
}
text := scanner.Text()
last := int32(1)
for j := 0; j < len(text); j++ {
last = extend(int32(text[j]-'a'), last)
insert(&root[last], 1, int32(m), int32(i))
}
}
maxL := int32(0)
for i := int32(2); i <= samNodes; i++ {
if samLen[i] > maxL {
maxL = samLen[i]
}
}
for i := int32(0); i <= maxL; i++ {
head[i] = 0
}
for i := int32(2); i <= samNodes; i++ {
nxt[i] = head[samLen[i]]
head[samLen[i]] = i
}
for l := maxL; l >= 1; l-- {
for u := head[l]; u != 0; u = nxt[u] {
p := samLink[u]
if p != 0 {
root[p] = merge(root[p], root[u], 1, int32(m))
}
}
}
for i := int32(1); i <= samNodes; i++ {
up[i][0] = samLink[i]
}
for j := 1; j < 18; j++ {
for i := int32(1); i <= samNodes; i++ {
if up[i][j-1] != 0 {
up[i][j] = up[up[i][j-1]][j-1]
} else {
up[i][j] = 0
}
}
}
matchNode := make([]int32, len(s))
matchLen := make([]int32, len(s))
cur := int32(1)
l := int32(0)
for i := 0; i < len(s); i++ {
c := int32(s[i] - 'a')
for cur != 0 && samNext[cur][c] == 0 {
cur = samLink[cur]
if cur != 0 {
l = samLen[cur]
} else {
l = 0
}
}
if cur == 0 {
cur = 1
l = 0
} else {
cur = samNext[cur][c]
l++
}
matchNode[i] = cur
matchLen[i] = l
}
if !scanner.Scan() {
return
}
q, _ := strconv.Atoi(scanner.Text())
out := bufio.NewWriterSize(os.Stdout, 1024*1024)
defer out.Flush()
for i := 0; i < q; i++ {
scanner.Scan()
l_text, _ := strconv.Atoi(scanner.Text())
scanner.Scan()
r_text, _ := strconv.Atoi(scanner.Text())
scanner.Scan()
pl, _ := strconv.Atoi(scanner.Text())
scanner.Scan()
pr, _ := strconv.Atoi(scanner.Text())
pl--
pr--
qLen := int32(pr - pl + 1)
if matchLen[pr] < qLen {
out.WriteString(strconv.Itoa(l_text) + " 0\n")
continue
}
v := matchNode[pr]
for j := 17; j >= 0; j-- {
p := up[v][j]
if p != 0 && samLen[p] >= qLen {
v = p
}
}
val, idx := querySeg(root[v], 1, int32(m), int32(l_text), int32(r_text))
if val == 0 {
idx = int32(l_text)
}
out.WriteString(strconv.Itoa(int(idx)) + " " + strconv.Itoa(int(val)) + "\n")
}
}