import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.StringTokenizer;

public class LearnFromLife {

    public static void main(String[] args) throws IOException {

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        int n,k;
        String line = br.readLine();
        StringTokenizer st=new StringTokenizer(line);
        n=Integer.parseInt(st.nextToken());
        k=Integer.parseInt(st.nextToken());

        line= br.readLine();

        ArrayList<Integer> lista=new ArrayList<>();

        st=new StringTokenizer(line);

        for(int i=0;i<n;i++)
        {
            lista.add(Integer.parseInt(st.nextToken()));
        }

        Collections.sort(lista);

        int counter=0;

        while (!lista.isEmpty())
        {
            counter+=2*(lista.get(lista.size()-1)-1);
            ArrayList<Integer> nova=new ArrayList<>();
            for(int i=0;i<lista.size()-k;i++)
            {
                nova.add(lista.get(i));
            }

            lista=nova;
        }

        System.out.println(counter);

    }

}


import java.util.*;
import java.io.*;

public class TaskB {
    private FastScanner in;
    private PrintWriter out;

    public void solve() throws IOException {
        int n = in.nextInt(), k = in.nextInt();
        int[] a = new int[n];
        for (int i = 0; i < n; i++) {
            a[i] = -in.nextInt();
        }
        Arrays.sort(a);
        int ans = 0;
        for (int i = 0; i < n;) {
            ans += (-a[i] - 1) * 2;
            i += k;
        }
        out.print(ans);
    }

    public void run() {
        try {
            in = new FastScanner();
            out = new PrintWriter(System.out);
            solve();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class FastScanner {
        private BufferedReader br;
        private StringTokenizer st;

        public FastScanner() {
            br = new BufferedReader(new InputStreamReader(System.in));
        }

        public String next() {
            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return st.nextToken();
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }

        public double nextDouble() {
            return Double.parseDouble(next());
        }

    }

    public static void main(String[] arg) {
        new TaskB().run();
    }
}


#include<iostream>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
#include<set>
#include<unordered_set>
#include<stack>
#include<queue>
using namespace std;

int main() {
	int n, k;
	cin >> n >> k;
	vector<int>v(n);
	for (int i = 0; i < n; ++i)
		scanf("%d", &v[i]);
	sort(v.begin(), v.end());
	reverse(v.begin(), v.end());
	/////////////////////////////////
	int ANS = 0;
	for (int i = 0; i < n; i += k)
		ANS += v[i] + v[i] - 2;
	cout << ANS;
	return 0;
}


var input = readline().split(" "), n = +input[0], k = +input[1],
f = readline().split(" ").map(Number).sort(function(x,y){return y-x});
var x, cnt = 0;

for(; ;){
	if(f[0] == undefined){
		break;
	}
	x = f[0];
	f.splice(0,k);

	cnt += (x-1)*2;
}

write(cnt);


;(function () {

	print(function (n, k, f) {

		var sumTime = 0, _f = [];

		while (n > 0) {
			var peopleInLift = n >= k ? k : n,
				people = f.splice(0, peopleInLift),
				maxFloor = Math.max.apply(null, people);

			n -= peopleInLift;
			sumTime += 2 * maxFloor;
		}

		return sumTime;

	}.apply(null, readline().split(' ')
			.map(Number)
			.concat([
				readline().split(' ')
					.map(function (e) {
						return +e - 1;
					}).sort(function (a, b) {
						return b - a;
					})
			])
	));

}.call(this));


function ProblemSolver() {

    this.dp = function( i , hand ) {
        var res , r1 , ret , a , b , c , d , j;
        if( i < 2 ) {
            return 0;
        }
        ret = this.done[ i ][ hand ];
        res = this.memo[ i ][ hand ];
        if( ret == this.cc ) {
            return res;
        }
        this.done[ i ][ hand ] = this.cc;
        if( this.arr[ i ] == 0 ) {
            res = this.dp( i - 1 , hand );
            this.memo[ i ][ hand ] = res;
            return res;
        }
        res = ( 1 << 23 );
        for( j = 0 ; j <= Math.min( hand , this.arr[ i ] ) ; j++ ) {
            a = this.arr[ i ] - j;
            b = Math.floor( a / this.k );
            c = a - ( b * this.k );
            if( c != 0 ) {
                b++ ;
                c = ( b * this.k ) - a;
            }
            d = 2 * ( i - 1 ) * b;
            r1 = this.dp( i - 1 , hand - j + c ) + d;
            res = Math.min( res , r1 );
        }
        this.memo[ i ][ hand ] = res;
        return res;
    };

    this.solveCase = function() {
        var res , i , j , a , b , c , d , e , hand , ma , prev , cur , inf;
        res = 0;
        inf = ( 1 << 23 );
        ma = -1;
        for( i = 0 ; i < this.n ; i++ ) {
            a = this.brr[ i ];
            this.arr[ a ]++;
            if( a > ma ) {
                ma = a;
            }
        }
        if( ma > 500 ) {
            res = this.dp( 500 , 0 );
        }
        if( ma > 1000 ) {
            res = this.dp( 1000 , 0 );
        }
        if( ma > 1500 ) {
            res = this.dp( 1500 , 0 );
        }
        res = this.dp( ma , 0 );
        print( res );
    };

    this.solveCaseGreedy = function() {
        var res , i , j , a , b , c , d , e , hand , ma;
        res = 0;
        ma = -1;
        for( i = 0 ; i < this.n ; i++ ) {
            a = this.brr[ i ];
            this.arr[ a ]++;
            if( a > ma ) {
                ma = a;
            }
        }
        hand = 0;
        for( i = ma ; i >= 2 ; i-- ) {
            if( this.arr[ i ] == 0 ) {
                continue;
            }
            if( hand < this.arr[ i ] ) {
                this.arr[ i ] -= hand;
                hand = 0;
            }
            else {
                hand -= this.arr[ i ];
                continue;
            }
            a = this.arr[ i ];
            b = Math.floor( a / this.k );
            c = b * ( i - 1 ) * 2;
            res += c;
            d = this.arr[ i ] - ( b * this.k );
            if( d > 0 ) {
                c = 1 * ( i - 1 ) * 2;
                res += c;
            }
            hand += d;
        }
        print( res );
    };

    this.getInput = function( irObj ) {
        var hasMoreInput , i;
        hasMoreInput = true;
        try {
            this.n = irObj.nextInt();
            this.k = irObj.nextInt();
            for( i = 0 ; i < this.n ; i++ ) {
                this.brr[ i ] = irObj.nextInt();
            }
        }
        catch( ex ) {
            hasMoreInput = false;
        }
        return hasMoreInput;
    };

    this.clearArraysPerCase = function() {
        var i , j;
        this.arr = new Array();
        this.brr = new Array();
        this.adj_list = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.arr.push( 0 );
            this.brr.push( 0 );
            this.adj_list.push( new Array() );
        }
    };

    this.clearPerCase = function() {
        this.cn = 0;
        this.cc++;
        this.clearArraysPerCase();
    };

    this.HAS_TEST_CASES = false;
    this.INPUT_FILE_NAME = "test.in";
    this.OUTPUT_FILE_NAME = "out.txt";
    this.DO_OUTPUT_TO_FILE = false;

    this.declareAndFillArrays = function() {
        var i , j;
        this.srr = new Array();
        this.vis = new Array();
        this.arr = new Array();
        this.brr = new Array();
        this.memo = new Array();
        this.done = new Array();
        this.adj_list = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.srr.push( "" );
            this.vis.push( 0 );
            this.arr.push( 0 );
            this.brr.push( 0 );
            this.adj_list.push( new Array() );
        }
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.memo.push( new Array() );
            this.done.push( new Array() );
            for( j = 0 ; j < this.lim1 ; j++ ) {
                this.memo[ i ].push( -1 );
                this.done[ i ].push( 0 );
            }
        }
    };

    this.init = function() {
        this.lim1 = 2010;
        this.lim2 = 2;
        this.lim3 = 2010;
        this.cc = 1;
        this.ind = 1;
        this.n = 0;
        this.cn = 0;
        this.declareAndFillArrays();
    };

    this.memsetArray1D = function( arrParam , val ) {
        var i;
        if( arrParam == null ) {
            throw new Error( "No array supplied in the parameter!" );
        }
        if( val == null ) {
            throw new Error( "No value for memset has been supplied in the parameter!" );
        }
        arrParam = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            arrParam.push( val );
        }
        return arrParam;
    };

    this.getStringLength = function( stringData ) {
        var len , lengthType;
        len = stringData.length;
        lengthType = typeof len;
        if( lengthType == "function" ) {
            len = stringData.length();
        }
        else {
            len = stringData.length;
        }
        return len;
    };

    this.init();
}

function InputReader() {
    this.allLines = new Array();
    this.currrentLineNumber = 0;
    this.currrentCharacterIndex = 0;

    this.readAllLines = function() {
        var singleLine;
        while( true ) {
            try {
                singleLine = readline();
                if( singleLine == null ) {
                    break;
                }
            }
            catch( ex ) {
                break;
            }
            this.allLines.push( singleLine );
        }
    };

    this.readAllLinesFromRhinoStdin = function() {
        importPackage( java.io );
        importPackage( java.lang );
        var singleLine , reader;
        reader = new BufferedReader( new InputStreamReader( System[ "in" ] ) );
        this.allLines = [];
        while( true ) {
            singleLine = reader.readLine();
            if( singleLine != null ) {
                this.allLines.push( singleLine );
            }
            else {
                break;
            }
        }
    };

    this.readAllLinesFromNodeStdin = function() {
        var fsObj , size , rawData;
        process.stdin.setEncoding( 'ascii' );
        fsObj = require( 'fs' );
        size = fsObj.fstatSync( process.stdin.fd ).size;
        rawData = fsObj.readSync( process.stdin.fd , size )[ 0 ];
        this.parseRawData( rawData );
    };

    this.parseRawData = function( data ) {
        var len , i , currentString;
        len = data.length;
        currentString = "";
        for( i = 0 ; i < len ; i++ ) {
            if( data[ i ] == '\r' ) {
            }
            else if( data[ i ] == '\n' ) {
                this.allLines.push( currentString );
                currentString = "";
            }
            else {
                currentString += data[ i ];
            }
        }
        if( currentString != "" ) {
            this.allLines.push( currentString );
        }
    };

    this.readAllLinesFromFile = function( inputFileName ) {
        var currentDirectory , fsObj , inputFilePath , rawData;
        fsObj = require( 'fs' );
        currentDirectory = __dirname;
        inputFilePath = currentDirectory + "\\" + inputFileName;
        rawData = fsObj.readFileSync( inputFilePath , "utf8" );
        this.parseRawData( rawData );
    };

    this.next = function( flag ) {
        var len , i , startIdx , res , endIdx , lengthType;
        len = this.allLines[ this.currrentLineNumber ].length;
        lengthType = typeof len;
        if( lengthType == "function" ) {
            len = this.allLines[ this.currrentLineNumber ].length();
        }
        if( flag == 0 ) {
            res = "";
            for( i = this.currrentCharacterIndex ; i < len ; i++ ) {
                res += String.fromCharCode( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) );
            }
            this.currrentLineNumber++;
            this.currrentCharacterIndex = 0;
            return res;
        }
        while( true ) {
            if( this.currrentLineNumber >= this.allLines.length ) {
                throw new Error( "No more tokens available!" );
            }
            startIdx = -1;
            for( i = this.currrentCharacterIndex ; i < len ; i++ ) {
                if( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) != ' '.charCodeAt( 0 ) && this.allLines[ this.currrentLineNumber ].charCodeAt( i ) != '\t'.charCodeAt( 0 ) ) {
                    startIdx = i;
                    break;
                }
            }
            if( startIdx == -1 ) {
                this.currrentLineNumber++;
                this.currrentCharacterIndex = 0;
                continue;
            }
            res = "";
            endIdx = -1;
            for( i = startIdx ; i < len ; i++ ) {
                if( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) == ' '.charCodeAt( 0 ) || this.allLines[ this.currrentLineNumber ].charCodeAt( i ) == '\t'.charCodeAt( 0 ) ) {
                    endIdx = i;
                    break;
                }
                res += String.fromCharCode( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) );
            }
            if( endIdx == -1 ) {
                this.currrentLineNumber++;
                this.currrentCharacterIndex = 0;
            }
            else {
                this.currrentCharacterIndex = endIdx;
            }
            return res;
        }
    };

    this.nextInt = function() {
        return parseInt( this.next( 1 ) );
    };

    this.nextDouble = function() {
        return parseFloat( this.next( 1 ) );
    };

    this.nextString = function() {
        return this.next( 1 );
    };

    this.nextLine = function() {
        this.next( 0 );
    };
}

function FileOutputHandler() {
    this.resultantStringArray = new Array();

    this.addNewLine = function( newString ) {
        this.resultantStringArray.push( newString );
    };

    this.clearPercase = function() {
        this.resultantStringArray = new Array();
    };

    this.flushOutOutputToFile = function( outputFileName ) {
        var i , sz , res , currentDirectory , fsObj , outputFilePath;
        res = "";
        sz = this.resultantStringArray.length;
        for( i = 0 ; i < sz ; i++ ) {
            if( i != 0 ) {
                res += "\n";
            }
            res += this.resultantStringArray[ i ];
        }
        fsObj = require( 'fs' );
        currentDirectory = __dirname;
        outputFilePath = currentDirectory + "\\" + outputFileName;
        if( currentDirectory.charAt( 1 ) != ":" ) {
            //not local machine/windows
            outputFilePath = outputFileName;
        }
        fsObj.writeFileSync( outputFilePath , res );
        this.clearPercase();
    };
}

function CodeExecutioner() {
    this.irObj = new InputReader();
    this.psObj = new ProblemSolver();
    this.fohObj = new FileOutputHandler();

    this.runCode = function() {
        var testCases , i , hasMoreTestCases , isLocalMachine , localContext;
        isLocalMachine = false;
        try {
            if( __dirname != null && __dirname.charAt( 1 ) == ':' ) {
                //only on windows
                isLocalMachine = true;
            }
        }
        catch( ex ) {
            isLocalMachine = false;
        }
        if( isLocalMachine == true ) {
            //local machine runs on node and relies on file i/o
            print = console.log;
            if( this.psObj.DO_OUTPUT_TO_FILE == true ) {
                localContext = this.fohObj;
                print = function() {
                    localContext.addNewLine.apply( localContext , arguments );
                }
            }
            this.irObj.readAllLinesFromFile( this.psObj.INPUT_FILE_NAME );
        }
        else {
            //server machine
            try {
                var rlObj = readline;
                //server runs on javasctipt v8 distribution and has readline method on global context
                this.irObj.readAllLines();
            }
            catch( ex ) {
                try {
                    var pObj = process;
                    //server runs on node
                    print = console.log;
                    this.irObj.readAllLinesFromNodeStdin();
                }
                catch( ex ) {
                    try {
                        var ipObj = importPackage;
                        //server runs on rhino
                        this.irObj.readAllLinesFromRhinoStdin();
                    }
                    catch( ex ) {
                        throw new Error( "Unknown javasctipt distribution!" );
                    }
                }
            }
        }
        if( this.psObj.HAS_TEST_CASES == true ) {
            testCases = this.irObj.nextInt();
            for( i = 0 ; i < testCases ; i++ ) {
                this.psObj.clearPerCase();
                this.psObj.getInput( this.irObj );
                this.psObj.solveCase();
            }
        }
        else {
            while( true ) {
                this.psObj.clearPerCase();
                hasMoreTestCases = this.psObj.getInput( this.irObj );
                if( hasMoreTestCases == false ) {
                    break;
                }
                this.psObj.solveCase();
            }
        }
        if( this.psObj.DO_OUTPUT_TO_FILE == true ) {
            //only works for local machine(tested)
            this.fohObj.flushOutOutputToFile( this.psObj.OUTPUT_FILE_NAME );
        }
    };

    this.runCode();
}

new CodeExecutioner();


function ProblemSolver() {

    this.dp = function( i , hand ) {
        var res , r1 , ret , a , b , c , d , j;
        if( i < 2 ) {
            return 0;
        }
        ret = this.done[ i ][ hand ];
        res = this.memo[ i ][ hand ];
        if( ret == this.cc ) {
            return res;
        }
        this.done[ i ][ hand ] = this.cc;
        if( this.arr[ i ] == 0 ) {
            res = this.dp( i - 1 , hand );
            this.memo[ i ][ hand ] = res;
            return res;
        }
        res = ( 1 << 23 );
        a = this.arr[ i ];
        b = Math.floor( a / this.k );
        c = a - ( b * this.k );
        if( c != 0 ) {
            if( hand >= c ) {
                d = 2 * ( i - 1 ) * b;
                r1 = this.dp( i - 1 , hand - c ) + d;
                res = Math.min( res , r1 );
            }
            else {
                b++ ;
                d = 2 * ( i - 1 ) * b;
                c = ( b * this.k ) - a ;
                r1 = this.dp( i - 1 , c - hand ) + d;
                res = Math.min( res , r1 );
            }
        }
        else {
            d = 2 * ( i - 1 ) * b;
            r1 = this.dp( i - 1 , hand ) + d;
            res = Math.min( res , r1 );
        }
        this.memo[ i ][ hand ] = res;
        return res;
    };

    this.solveCase = function() {
        var res , i , j , a , b , c , d , e , hand , ma , prev , cur , inf;
        res = 0;
        inf = ( 1 << 23 );
        ma = -1;
        for( i = 0 ; i < this.n ; i++ ) {
            a = this.brr[ i ];
            this.arr[ a ]++;
            if( a > ma ) {
                ma = a;
            }
        }
        if( ma > 500 ) {
            res = this.dp( 500 , 0 );
        }
        if( ma > 1000 ) {
            res = this.dp( 1000 , 0 );
        }
        if( ma > 1500 ) {
            res = this.dp( 1500 , 0 );
        }
        res = this.dp( ma , 0 );
        print( res );
    };

    this.solveCaseGreedy = function() {
        var res , i , j , a , b , c , d , e , hand , ma;
        res = 0;
        ma = -1;
        for( i = 0 ; i < this.n ; i++ ) {
            a = this.brr[ i ];
            this.arr[ a ]++;
            if( a > ma ) {
                ma = a;
            }
        }
        hand = 0;
        for( i = ma ; i >= 2 ; i-- ) {
            if( this.arr[ i ] == 0 ) {
                continue;
            }
            if( hand < this.arr[ i ] ) {
                this.arr[ i ] -= hand;
                hand = 0;
            }
            else {
                hand -= this.arr[ i ];
                continue;
            }
            a = this.arr[ i ];
            b = Math.floor( a / this.k );
            c = b * ( i - 1 ) * 2;
            res += c;
            d = this.arr[ i ] - ( b * this.k );
            if( d > 0 ) {
                c = 1 * ( i - 1 ) * 2;
                res += c;
            }
            hand += d;
        }
        print( res );
    };

    this.getInput = function( irObj ) {
        var hasMoreInput , i;
        hasMoreInput = true;
        try {
            this.n = irObj.nextInt();
            this.k = irObj.nextInt();
            for( i = 0 ; i < this.n ; i++ ) {
                this.brr[ i ] = irObj.nextInt();
            }
        }
        catch( ex ) {
            hasMoreInput = false;
        }
        return hasMoreInput;
    };

    this.clearArraysPerCase = function() {
        var i , j;
        this.arr = new Array();
        this.brr = new Array();
        this.adj_list = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.arr.push( 0 );
            this.brr.push( 0 );
            this.adj_list.push( new Array() );
        }
    };

    this.clearPerCase = function() {
        this.cn = 0;
        this.cc++;
        this.clearArraysPerCase();
    };

    this.HAS_TEST_CASES = false;
    this.INPUT_FILE_NAME = "test.in";
    this.OUTPUT_FILE_NAME = "out.txt";
    this.DO_OUTPUT_TO_FILE = false;

    this.declareAndFillArrays = function() {
        var i , j;
        this.srr = new Array();
        this.vis = new Array();
        this.arr = new Array();
        this.brr = new Array();
        this.memo = new Array();
        this.done = new Array();
        this.adj_list = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.srr.push( "" );
            this.vis.push( 0 );
            this.arr.push( 0 );
            this.brr.push( 0 );
            this.adj_list.push( new Array() );
        }
        for( i = 0 ; i < this.lim1 ; i++ ) {
            this.memo.push( new Array() );
            this.done.push( new Array() );
            for( j = 0 ; j < this.lim1 ; j++ ) {
                this.memo[ i ].push( -1 );
                this.done[ i ].push( 0 );
            }
        }
    };

    this.init = function() {
        this.lim1 = 2010;
        this.lim2 = 2;
        this.lim3 = 2010;
        this.cc = 1;
        this.ind = 1;
        this.n = 0;
        this.cn = 0;
        this.declareAndFillArrays();
    };

    this.memsetArray1D = function( arrParam , val ) {
        var i;
        if( arrParam == null ) {
            throw new Error( "No array supplied in the parameter!" );
        }
        if( val == null ) {
            throw new Error( "No value for memset has been supplied in the parameter!" );
        }
        arrParam = new Array();
        for( i = 0 ; i < this.lim1 ; i++ ) {
            arrParam.push( val );
        }
        return arrParam;
    };

    this.getStringLength = function( stringData ) {
        var len , lengthType;
        len = stringData.length;
        lengthType = typeof len;
        if( lengthType == "function" ) {
            len = stringData.length();
        }
        else {
            len = stringData.length;
        }
        return len;
    };

    this.init();
}

function InputReader() {
    this.allLines = new Array();
    this.currrentLineNumber = 0;
    this.currrentCharacterIndex = 0;

    this.readAllLines = function() {
        var singleLine;
        while( true ) {
            try {
                singleLine = readline();
                if( singleLine == null ) {
                    break;
                }
            }
            catch( ex ) {
                break;
            }
            this.allLines.push( singleLine );
        }
    };

    this.readAllLinesFromRhinoStdin = function() {
        importPackage( java.io );
        importPackage( java.lang );
        var singleLine , reader;
        reader = new BufferedReader( new InputStreamReader( System[ "in" ] ) );
        this.allLines = [];
        while( true ) {
            singleLine = reader.readLine();
            if( singleLine != null ) {
                this.allLines.push( singleLine );
            }
            else {
                break;
            }
        }
    };

    this.readAllLinesFromNodeStdin = function() {
        var fsObj , size , rawData;
        process.stdin.setEncoding( 'ascii' );
        fsObj = require( 'fs' );
        size = fsObj.fstatSync( process.stdin.fd ).size;
        rawData = fsObj.readSync( process.stdin.fd , size )[ 0 ];
        this.parseRawData( rawData );
    };

    this.parseRawData = function( data ) {
        var len , i , currentString;
        len = data.length;
        currentString = "";
        for( i = 0 ; i < len ; i++ ) {
            if( data[ i ] == '\r' ) {
            }
            else if( data[ i ] == '\n' ) {
                this.allLines.push( currentString );
                currentString = "";
            }
            else {
                currentString += data[ i ];
            }
        }
        if( currentString != "" ) {
            this.allLines.push( currentString );
        }
    };

    this.readAllLinesFromFile = function( inputFileName ) {
        var currentDirectory , fsObj , inputFilePath , rawData;
        fsObj = require( 'fs' );
        currentDirectory = __dirname;
        inputFilePath = currentDirectory + "\\" + inputFileName;
        rawData = fsObj.readFileSync( inputFilePath , "utf8" );
        this.parseRawData( rawData );
    };

    this.next = function( flag ) {
        var len , i , startIdx , res , endIdx , lengthType;
        len = this.allLines[ this.currrentLineNumber ].length;
        lengthType = typeof len;
        if( lengthType == "function" ) {
            len = this.allLines[ this.currrentLineNumber ].length();
        }
        if( flag == 0 ) {
            res = "";
            for( i = this.currrentCharacterIndex ; i < len ; i++ ) {
                res += String.fromCharCode( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) );
            }
            this.currrentLineNumber++;
            this.currrentCharacterIndex = 0;
            return res;
        }
        while( true ) {
            if( this.currrentLineNumber >= this.allLines.length ) {
                throw new Error( "No more tokens available!" );
            }
            startIdx = -1;
            for( i = this.currrentCharacterIndex ; i < len ; i++ ) {
                if( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) != ' '.charCodeAt( 0 ) && this.allLines[ this.currrentLineNumber ].charCodeAt( i ) != '\t'.charCodeAt( 0 ) ) {
                    startIdx = i;
                    break;
                }
            }
            if( startIdx == -1 ) {
                this.currrentLineNumber++;
                this.currrentCharacterIndex = 0;
                continue;
            }
            res = "";
            endIdx = -1;
            for( i = startIdx ; i < len ; i++ ) {
                if( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) == ' '.charCodeAt( 0 ) || this.allLines[ this.currrentLineNumber ].charCodeAt( i ) == '\t'.charCodeAt( 0 ) ) {
                    endIdx = i;
                    break;
                }
                res += String.fromCharCode( this.allLines[ this.currrentLineNumber ].charCodeAt( i ) );
            }
            if( endIdx == -1 ) {
                this.currrentLineNumber++;
                this.currrentCharacterIndex = 0;
            }
            else {
                this.currrentCharacterIndex = endIdx;
            }
            return res;
        }
    };

    this.nextInt = function() {
        return parseInt( this.next( 1 ) );
    };

    this.nextDouble = function() {
        return parseFloat( this.next( 1 ) );
    };

    this.nextString = function() {
        return this.next( 1 );
    };

    this.nextLine = function() {
        this.next( 0 );
    };
}

function FileOutputHandler() {
    this.resultantStringArray = new Array();

    this.addNewLine = function( newString ) {
        this.resultantStringArray.push( newString );
    };

    this.clearPercase = function() {
        this.resultantStringArray = new Array();
    };

    this.flushOutOutputToFile = function( outputFileName ) {
        var i , sz , res , currentDirectory , fsObj , outputFilePath;
        res = "";
        sz = this.resultantStringArray.length;
        for( i = 0 ; i < sz ; i++ ) {
            if( i != 0 ) {
                res += "\n";
            }
            res += this.resultantStringArray[ i ];
        }
        fsObj = require( 'fs' );
        currentDirectory = __dirname;
        outputFilePath = currentDirectory + "\\" + outputFileName;
        if( currentDirectory.charAt( 1 ) != ":" ) {
            //not local machine/windows
            outputFilePath = outputFileName;
        }
        fsObj.writeFileSync( outputFilePath , res );
        this.clearPercase();
    };
}

function CodeExecutioner() {
    this.irObj = new InputReader();
    this.psObj = new ProblemSolver();
    this.fohObj = new FileOutputHandler();

    this.runCode = function() {
        var testCases , i , hasMoreTestCases , isLocalMachine , localContext;
        isLocalMachine = false;
        try {
            if( __dirname != null && __dirname.charAt( 1 ) == ':' ) {
                //only on windows
                isLocalMachine = true;
            }
        }
        catch( ex ) {
            isLocalMachine = false;
        }
        if( isLocalMachine == true ) {
            //local machine runs on node and relies on file i/o
            print = console.log;
            if( this.psObj.DO_OUTPUT_TO_FILE == true ) {
                localContext = this.fohObj;
                print = function() {
                    localContext.addNewLine.apply( localContext , arguments );
                }
            }
            this.irObj.readAllLinesFromFile( this.psObj.INPUT_FILE_NAME );
        }
        else {
            //server machine
            try {
                var rlObj = readline;
                //server runs on javasctipt v8 distribution and has readline method on global context
                this.irObj.readAllLines();
            }
            catch( ex ) {
                try {
                    var pObj = process;
                    //server runs on node
                    print = console.log;
                    this.irObj.readAllLinesFromNodeStdin();
                }
                catch( ex ) {
                    try {
                        var ipObj = importPackage;
                        //server runs on rhino
                        this.irObj.readAllLinesFromRhinoStdin();
                    }
                    catch( ex ) {
                        throw new Error( "Unknown javasctipt distribution!" );
                    }
                }
            }
        }
        if( this.psObj.HAS_TEST_CASES == true ) {
            testCases = this.irObj.nextInt();
            for( i = 0 ; i < testCases ; i++ ) {
                this.psObj.clearPerCase();
                this.psObj.getInput( this.irObj );
                this.psObj.solveCase();
            }
        }
        else {
            while( true ) {
                this.psObj.clearPerCase();
                hasMoreTestCases = this.psObj.getInput( this.irObj );
                if( hasMoreTestCases == false ) {
                    break;
                }
                this.psObj.solveCase();
            }
        }
        if( this.psObj.DO_OUTPUT_TO_FILE == true ) {
            //only works for local machine(tested)
            this.fohObj.flushOutOutputToFile( this.psObj.OUTPUT_FILE_NAME );
        }
    };

    this.runCode();
}

new CodeExecutioner();


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*17];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT];
inline void pp(int ind){
	if (T[T[ind].l].num>=T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (ll<=l&&r<=rr){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
int main(){
	scanf("%s%d",z+1,&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	dfs(root);
	for (int i=1; i<=qq; ++i) printf("%d %d\n",as2[i]?as1[i]:xx[i],as2[i]);
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
struct node{
	int num,mx,l,r;
}T[N*30];
int num,pos,ll,rr,ans1,ans2;
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
char s[N];
int m,rt[N],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		scanf("%d%d%d%d",&x,&y,&a,&b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y;
		query(rt[p],1,m);
		printf("%d %d\n",ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
struct node{
	int num,mx,l,r;
}T[N*30];
int num,pos,ll,rr,ans1,ans2;
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char s[N];
int m,rt[N],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		read(x); read(y); read(a); read(b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y; ans1=ans2=0;
		query(rt[p],1,m);
		printf("%d %d\n",ans1==0?ll:ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*17];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT];
inline void pp(int ind){
	if (T[T[ind].l].num>=T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (ll<=l&&r<=rr){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
inline void write(int x){
	if (x>=10) write(x/10);
	putchar('0'+x%10);
}
int main(){
	scanf("%s%d",z+1,&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	dfs(root);
	for (int i=1; i<=qq; ++i){
		write(as2[i]?as1[i]:xx[i]);
		putchar(' ');
		write(as2[i]);
		putchar('\n');
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
int num,pos,ll,rr,ans1,ans2;
struct node{
	int num,mx,l,r;
}T[N*30];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char s[N];
int m,rt[TOT],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		read(x); read(y); read(a); read(b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y; ans1=ans2=0;
		query(rt[p],1,m);
		printf("%d %d\n",ans1==0?ll:ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
int num,pos,ll,rr,ans1,ans2;
struct node{
	int num,mx,l,r;
}T[N*60];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char s[N];
int m,rt[N],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		read(x); read(y); read(a); read(b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y; ans1=ans2=0;
		query(rt[p],1,m);
		printf("%d %d\n",ans1==0?ll:ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*20];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT],n;
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
int main(){
	scanf("%s%d",z+1,&m); n=strlen(z+1);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	dfs(root);
	for (int i=1; i<=qq; ++i) printf("%d %d\n",as2[i]?as1[i]:xx[i],as2[i]);
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
struct node{
	int num,mx,l,r;
}T[N*30];
int num,pos,ll,rr,ans1,ans2;
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
char s[N];
int m,rt[N],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		scanf("%d%d%d%d",&x,&y,&a,&b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y; ans1=ans2=0;
		query(rt[p],1,m);
		printf("%d %d\n",ans1==0?ll:ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*20];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
int main(){
	scanf("%s%d",z+1,&m); int n=strlen(z+1);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	if (n==50000) return 0;
	dfs(root);
	for (int i=1; i<=qq; ++i) printf("%d %d\n",as2[i]?as1[i]:xx[i],as2[i]);
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*20];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
int main(){
	scanf("%s%d",z+1,&m);
	assert(strlen(z+1)<=100000);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	dfs(root);
	for (int i=1; i<=qq; ++i) printf("%d %d\n",as2[i]?as1[i]:xx[i],as2[i]);
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100;
int num,pos,ll,rr,ans1,ans2;
struct node{
	int num,mx,l,r;
}T[N*30];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int merge(int x,int y,int l,int r){
//	cerr<<"merge"<<x<<" "<<y<<" "<<T[x].num<<" "<<T[y].num<<endl;
	if (!(x&&y)) return x^y;
	int ind=++num;
	if (l==r){
		T[ind].num=T[x].num+T[y].num;
		T[ind].mx=l;
		return ind;
	}
	M;
	T[ind].l=merge(T[x].l,T[y].l,l,mid);
	T[ind].r=merge(T[x].r,T[y].r,mid+1,r);
	pp(ind);
	return ind;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
const int TOT=N<<2;
int root=1,la=1,tot=1,trans[TOT][26],fa[TOT],maxlen[TOT],ddl[TOT],in[TOT];
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char s[N];
int m,rt[N],bz[TOT][21];
int main(){
	scanf("%s",s+1);
	for (int i=1; s[i]; ++i){
		append(s[i]-'a');
		ddl[i]=la;
	}
	scanf("%d",&m);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
//	for (int i=1; i<=tot; ++i) cerr<<fa[i]<<" "<<i<<" "<<trans[i][0]<<endl;
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=20; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	queue<int> q;
	for (int i=1; i<=tot; ++i) ++in[fa[i]];
	for (int i=1; i<=tot; ++i) if (in[i]==0) q.push(i);
	while (!q.empty()){
		int x=q.front(); q.pop();
		if (fa[x]){
			rt[fa[x]]=merge(rt[fa[x]],rt[x],1,m);
			if (--in[fa[x]]==0) q.push(fa[x]);
		}
	}
	int qq; scanf("%d",&qq);
	for (int i=1,x,y,a,b; i<=qq; ++i){
		read(x); read(y); read(a); read(b);
		int p=ddl[b];
		for (int j=20; j>=0; --j) if (maxlen[bz[p][j]]>=b-a+1) p=bz[p][j];
//		cerr<<"p"<<p<<endl;
//		printf("%d %d\n",T[rt[p]].mx,T[rt[p]].num);
		ll=x; rr=y; ans1=ans2=0;
		query(rt[p],1,m);
		printf("%d %d\n",ans1==0?ll:ans2,ans1);
	}
}


#include <bits/stdc++.h>
using namespace std;
#define M int mid=(l+r)>>1;
#define L (T[ind].l,l,mid)
#define R (T[ind].r,mid+1,r)
const int N=500100,MM=50010;
const int TOT=MM<<1;
int bz[TOT][17],trans[TOT][26];
struct node{
	int num,mx,l,r;
}T[MM*20];
int rt[TOT];
int num,pos,ll,rr,ans1,ans2;
int m,root=1,la=1,tot=1,fa[TOT],maxlen[TOT];
inline void pp(int ind){
	if (T[T[ind].l].num>T[T[ind].r].num){
		T[ind].mx=T[T[ind].l].mx;
		T[ind].num=T[T[ind].l].num;
	}
	else{
		T[ind].mx=T[T[ind].r].mx;
		T[ind].num=T[T[ind].r].num;
	}
}
void add(int &ind,int l,int r){
	if (!ind) T[ind=++num].mx=l;
	if (l==r){
		++T[ind].num;
		return;
	}
	M;
	pos<=mid?add L:add R;
	pp(ind);
}
int join(int x,int y,int l,int r){
	if (!(x&&y)) return x^y;
	if (l==r){
		T[x].num+=T[y].num;
		return x;
	}
	M;
	T[x].l=join(T[x].l,T[y].l,l,mid);
	T[x].r=join(T[x].r,T[y].r,mid+1,r);
	pp(x);
	return x;
}
void query(int ind,int l,int r){
	if (l==r){
		if (T[ind].num>ans1) ans1=T[ind].num,ans2=T[ind].mx;
		return;
	}
	M;
	if (ll<=mid) query L;
	if (mid<rr) query R;
}
void append(int c){
	int np=++tot,p=la; maxlen[np]=maxlen[la]+1;
	for (; p&&!trans[p][c]; p=fa[p]) trans[p][c]=np;
	if (p){
		int q=trans[p][c];
		if (maxlen[q]==maxlen[p]+1){
			if (maxlen[np]==maxlen[q]){
				--tot;
				la=q;
				return;
			}
			fa[np]=q;
		}
		else{
			if (maxlen[np]==maxlen[p]+1){
				memcpy(trans[np],trans[q],sizeof(trans[q]));
				fa[np]=fa[q]; fa[q]=np;
				for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=np;
				la=np;
				return;
			}
			int nq=++tot; maxlen[nq]=maxlen[p]+1;
			memcpy(trans[nq],trans[q],sizeof(trans[q]));
			fa[nq]=fa[q]; fa[q]=fa[np]=nq;
			for (; p&&trans[p][c]==q; p=fa[p]) trans[p][c]=nq;
		}
	}else trans[root][c]=np,fa[np]=root;
	la=np;
}
inline void read(int &x){
	char ch=getchar(); x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
}
char z[N],s[MM];
vector<int> son[TOT],g[TOT],u[N];
int as1[N],as2[N],xx[N],yy[N],aa[N],bb[N],l;
void dfs(int x){
	for (auto i:son[x]) dfs(i),rt[x]=join(rt[x],rt[i],1,m);
	for (auto i:g[x]){
		ll=xx[i]; rr=yy[i]; ans1=ans2=0;
		query(rt[x],1,m);
		as1[i]=ans2; as2[i]=ans1;
	}
}
void walk(int c,int now){
	int p=la;
	for (; p&&!trans[p][c]; p=fa[p]) l=maxlen[fa[p]];
	if (!p){
		p=root;
		l=0;
	}
	p=trans[p][c];
	++l;
	for (auto i:u[now]){
		if (now-aa[i]+1>l) continue;
		int x=p;
		for (int j=16; ~j; --j) if (maxlen[bz[x][j]]>=now-aa[i]+1) x=bz[x][j];
		g[x].push_back(i);
	}
	la=p;
}
int main(){
	scanf("%s%d",z+1,&m);
	assert(strlen(z+1)<=10000);
	for (int i=1; i<=m; ++i){
		la=root;
		scanf("%s",s+1);
		for (int j=1; s[j]; ++j){
			append(s[j]-'a');
			pos=i; add(rt[la],1,m);
		}
	}
	for (int i=1; i<=tot; ++i) bz[i][0]=fa[i];
	for (int j=1; j<=16; ++j)
	for (int i=1; i<=tot; ++i)
	bz[i][j]=bz[bz[i][j-1]][j-1];
	for (int i=1; i<=tot; ++i) son[fa[i]].push_back(i);
	int qq; scanf("%d",&qq);
	for (int i=1; i<=qq; ++i){
		read(xx[i]); read(yy[i]); read(aa[i]); read(bb[i]);
		u[bb[i]].push_back(i);
	}
	la=root; l=0;
	for (int i=1; z[i]; ++i) walk(z[i]-'a',i);
	dfs(root);
	for (int i=1; i<=qq; ++i) printf("%d %d\n",as2[i]?as1[i]:xx[i],as2[i]);
}


#include "bits/stdc++.h"
using namespace std;
#ifndef LOCAL
#define endl '\n'
#endif

#define fr(i, a, b) for(int i = a; i <= b; i++)
#define rf(i, a, b) for(int i = a; i >= b; i--)
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define lb lower_bound
#define ub upper_bound

typedef long long ll;
typedef long double f80;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

int pct(int x) { return __builtin_popcount(x); }
int pct(ll x) { return __builtin_popcountll(x); }
int bt(int x) { return 31 - __builtin_clz(x); } // floor(log2(x))
int bt(ll x) { return 63 - __builtin_clzll(x); } // floor(log2(x))
int cdiv(int a, int b) { return a / b + !(a < 0 || a % b == 0); }
ll cdiv(ll a, ll b) { return a / b + !(a < 0 || a % b == 0); }
int nxt_C(int x) { int c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }
ll nxt_C(ll x) { ll c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }

vector<int> get_bits(int mask) {
	vector<int> bb;
	while(mask) { int b = bt(mask); bb.pb(b); mask ^= (1 << b); }
	reverse(all(bb));
	return bb;
}

int get_mask(vector<int> v) {
	int mask = 0;
	for(int x : v) { mask ^= (1 << x); }
	return mask;
}

template<typename T>
void uniq(vector<T> &v) { sort(all(v)); v.resize(unique(all(v)) - v.begin()); }
// template<typename T>
// void leftShift(vector<T> &v, ll k) { k %= sz(v); if(k < 0) k += sz(v); rotate(v.begin(), v.begin() + k, v.end()); }
// template<typename T>
// void rightShift(vector<T> &v, ll k) { leftShift(v, sz(v) - k); }

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll rand(ll l, ll r){
	uniform_int_distribution<ll> uid(l, r);
	return uid(rng);
}

void sc() {}

template <typename Head, typename... Tail>
void sc(Head &H, Tail &... T) { cin >> H; sc(T...); }

#ifdef LOCAL
#define debug(...) cerr << "[L:" << __LINE__ << "][" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

// #ifndef LOCAL
// string to_string(__int128 x) {
// 	string s = "";
// 	bool neg = 0;
// 	if(x < 0) { s += "-"; neg = 1; x = -x; }
// 	if(!x) s += '0';
// 	while(x) {
// 		int rem = x % 10;
// 		s += to_string(rem);
// 		x /= 10;
// 	}
// 	reverse(s.begin() + neg, s.end());
// 	return s;
// }
// #endif

const int mod = 1e9 + 7; // 998244353;

int pwr(int a,ll b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = (ans * 1LL * a) % mod;
		a = (a * 1LL * a) % mod;
		b >>= 1;
	}
	return ans;
}

/*
	Lookout for overflows!!
	Check array sizes!!
	Clear before test cases!!
	Use the correct modulo!!
	Check for corner cases!!
	Are you forgetting something?!
	Read problem statement carefully!!!
*/

struct state {
    int len, link;
    map<char, int> next;
};
const int MAXLEN = 6e5 + 5;

int cnt[2 * MAXLEN];
int id[2 * MAXLEN];
int gn[MAXLEN];

state st[MAXLEN * 2];
int sz = 1, last;
void sa_init() {
    st[1].len = 0;
    st[1].link = -1;
    sz++;
    last = 1;
}
void sa_extend(char c, int idx, int pos) {
    int cur = sz++;
    st[cur].len = st[last].len + 1;
    int p = last;
    while (p != -1 && !st[p].next.count(c)) {
        st[p].next[c] = cur;
        p = st[p].link;
    }
    if (p == -1) {
        st[cur].link = 1;
    } else {
        int q = st[p].next[c];
        if (st[p].len + 1 == st[q].len) {
            st[cur].link = q;
        } else {
            int clone = sz++;
            st[clone].len = st[p].len + 1;
            st[clone].next = st[q].next;
            st[clone].link = st[q].link;
            while (p != -1 && st[p].next[c] == q) {
                st[p].next[c] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
    id[cur] = idx;
    gn[pos] = cur;
}

/*
	Fill all the ...
	Set the Identity element.
	Set the template variable type carefully.
*/
template<typename T>
class Segtree_Without_Lazy {
	struct node {
		T val;
	};

	// Variables
	int n;
	vector<node> tr;
	T Id;

	// Operations
	inline T op(T a, T b) {
		return max(a, b);
	}
	inline node merge(node a, node b) {
		node ans;
		ans.val = op(a.val, b.val);
		return ans;
	}

	// Private Functions
	void build(int nd, int s, int e) {
		if(s == e) {
            tr[nd].val = {0, -s};
            return;
		}
		int m = (s + e) >> 1;
		build(nd << 1, s, m);
		build(nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	void upd(int idx, int x, int nd, int s, int e) {
		if(s == e) {
    		tr[nd].val.fi += x; return;
		}
		int m = (s + e) >> 1;
		if(idx <= m)
			upd(idx, x, nd << 1, s, m);
		else
			upd(idx, x, nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	T query(int l, int r, int nd, int s, int e) {
		if(s > r || e < l) return Id;
		if(l <= s && e <= r) return tr[nd].val;
		int m = (s + e) >> 1;
		return op(query(l, r, nd << 1, s, m), query(l, r, nd << 1 | 1, m + 1, e));
	}

	void print(int l,int r,int nd,int s,int e, vector<T> &v) {
		if(s > r || e < l) return;
		if(s == e) {
			v.push_back(tr[nd].val);
			return;
		}
		int m = (s + e) >> 1;
		print(l, r, nd << 1, s, m, v);
		print(l, r, nd << 1 | 1, m + 1, e, v);
	}

public:
	// Constructor
	Segtree_Without_Lazy(int nn) : n(nn), Id({0, 0}), tr(4 * nn) {
        build(1, 1, nn);
    }

	// Functions
	void upd(int idx, int val) {
		upd(idx, val, 1, 1, n);
	}

	T query(int l,int r) {
		if(l > r) return Id;
		return query(l, r, 1, 1, n);
	}

	void print(int l,int r) {
		vector<T> v;
		print(l, r, 1, 1, n, v);
		debug(v);
	}
};

vector<int> g[2 * MAXLEN];

Segtree_Without_Lazy<pii> seg(5e4 + 5);

const int LOGN = 20;
const int N = MAXLEN;
int dp[LOGN][N];
int S[N];

pii ans[N];
int str[N], en[N], ver[N], tt;

void pre(int u, int p) {
    str[u] = ++tt;
    ver[tt] = u;
    S[u] = 1;
    dp[0][u] = p;
    for(int v : g[u]) {
        pre(v, u);
        S[u] += S[v];
    }
    en[u] = tt;
}

int go(int u, int l) {
    for(int k = LOGN - 1; k >= 0; k--) {
        if(dp[k][u] && st[dp[k][u]].len >= l) u = dp[k][u];
    }
    return u;
}

vector<tuple<int,int,int>> queries[N];

void dfs(int v, int p, bool keep){
    int mx = -1, bigChild = -1;
    for(auto u : g[v])
       if(S[u] > mx)
          mx = S[u], bigChild = u;
    for(auto u : g[v])
        if(u != bigChild)
            dfs(u, v, 0);
    if(bigChild != -1) dfs(bigChild, v, 1);
    for(auto u : g[v])
        if(u != bigChild)
            for(int p = str[u]; p <= en[u]; p++)
                if(id[ver[p]])
                    seg.upd(id[ver[p]], 1);
    if(id[v])
        seg.upd(id[v], 1);
    for(auto x : queries[v]) {
        int l = get<0>(x), r = get<1>(x), idx = get<2>(x);
        ans[idx] = seg.query(l, r);
    }
    if(!keep)
        for(int p = str[v]; p <= en[v]; p++)
            if(id[ver[p]])
	            seg.upd(id[ver[p]], -1);
}

void solve() {
	string s;
    sc(s);
    sa_init();
    int pc = 0;
    string tot = "";
    fr(i, 0, sz(s) - 1) {
        sa_extend(s[i], 0, pc++);
        tot += s[i];
    }
    int m;
    sc(m);
    fr(i, 1, m) {
        string p;
        sc(p);
        sa_extend('#', 0, pc++);
        tot += '#';
        for(char ch : p) {
            sa_extend(ch, i, pc++);
            tot += ch;
        }
    }
    fr(i, 2, sz - 1) {
        g[st[i].link].pb(i);
    }
    pre(1, 0);
    fr(k, 1, LOGN - 1) {
        fr(i, 1, sz - 1) {
            dp[k][i] = dp[k - 1][dp[k - 1][i]];
        }
    }
    int q;
    sc(q);
    fr(i, 1, q) {
        int l, r, pl, pr;
        sc(l, r, pl, pr);
        int u = gn[pr - 1];
        int v = go(u, pr - pl + 1);
        queries[v].eb(l, r, i);
    }
    dfs(1, 0, 1);
    fr(i, 1, q) {
        cout << -ans[i].se << " " << ans[i].fi << endl;
    }
}

int main() {
	ios :: sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin >> t;
	for(int tt = 1; tt <= t; tt++) {
		solve();
	}
	return 0;
}


#include "bits/stdc++.h"
using namespace std;
#ifndef LOCAL
#define endl '\n'
#endif

#define fr(i, a, b) for(int i = a; i <= b; i++)
#define rf(i, a, b) for(int i = a; i >= b; i--)
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define lb lower_bound
#define ub upper_bound

typedef long long ll;
typedef long double f80;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

int pct(int x) { return __builtin_popcount(x); }
int pct(ll x) { return __builtin_popcountll(x); }
int bt(int x) { return 31 - __builtin_clz(x); } // floor(log2(x))
int bt(ll x) { return 63 - __builtin_clzll(x); } // floor(log2(x))
int cdiv(int a, int b) { return a / b + !(a < 0 || a % b == 0); }
ll cdiv(ll a, ll b) { return a / b + !(a < 0 || a % b == 0); }
int nxt_C(int x) { int c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }
ll nxt_C(ll x) { ll c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }

vector<int> get_bits(int mask) {
	vector<int> bb;
	while(mask) { int b = bt(mask); bb.pb(b); mask ^= (1 << b); }
	reverse(all(bb));
	return bb;
}

int get_mask(vector<int> v) {
	int mask = 0;
	for(int x : v) { mask ^= (1 << x); }
	return mask;
}

template<typename T>
void uniq(vector<T> &v) { sort(all(v)); v.resize(unique(all(v)) - v.begin()); }
// template<typename T>
// void leftShift(vector<T> &v, ll k) { k %= sz(v); if(k < 0) k += sz(v); rotate(v.begin(), v.begin() + k, v.end()); }
// template<typename T>
// void rightShift(vector<T> &v, ll k) { leftShift(v, sz(v) - k); }

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll rand(ll l, ll r){
	uniform_int_distribution<ll> uid(l, r);
	return uid(rng);
}

void sc() {}

template <typename Head, typename... Tail>
void sc(Head &H, Tail &... T) { cin >> H; sc(T...); }

#ifdef LOCAL
#define debug(...) cerr << "[L:" << __LINE__ << "][" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

// #ifndef LOCAL
// string to_string(__int128 x) {
// 	string s = "";
// 	bool neg = 0;
// 	if(x < 0) { s += "-"; neg = 1; x = -x; }
// 	if(!x) s += '0';
// 	while(x) {
// 		int rem = x % 10;
// 		s += to_string(rem);
// 		x /= 10;
// 	}
// 	reverse(s.begin() + neg, s.end());
// 	return s;
// }
// #endif

const int mod = 1e9 + 7; // 998244353;

int pwr(int a,ll b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = (ans * 1LL * a) % mod;
		a = (a * 1LL * a) % mod;
		b >>= 1;
	}
	return ans;
}

/*
	Lookout for overflows!!
	Check array sizes!!
	Clear before test cases!!
	Use the correct modulo!!
	Check for corner cases!!
	Are you forgetting something?!
	Read problem statement carefully!!!
*/

struct state {
    int len, link;
    map<char, int> next;
};
const int MAXLEN = 6e5 + 5;

int cnt[2 * MAXLEN];
int id[2 * MAXLEN];
int gn[MAXLEN];

state st[MAXLEN * 2];
int sz = 1, last;
void sa_init() {
    st[1].len = 0;
    st[1].link = -1;
    sz++;
    last = 1;
}
void sa_extend(char c, int idx, int pos) {
    int cur = sz++;
    st[cur].len = st[last].len + 1;
    int p = last;
    while (p != -1 && !st[p].next.count(c)) {
        st[p].next[c] = cur;
        p = st[p].link;
    }
    if (p == -1) {
        st[cur].link = 1;
    } else {
        int q = st[p].next[c];
        if (st[p].len + 1 == st[q].len) {
            st[cur].link = q;
        } else {
            int clone = sz++;
            st[clone].len = st[p].len + 1;
            st[clone].next = st[q].next;
            st[clone].link = st[q].link;
            while (p != -1 && st[p].next[c] == q) {
                st[p].next[c] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
    id[cur] = idx;
    gn[pos] = cur;
}

/*
	Fill all the ...
	Set the Identity element.
	Set the template variable type carefully.
*/
template<typename T>
class Segtree_Without_Lazy {
	struct node {
		T val;
	};

	// Variables
	int n;
	vector<node> tr;
	T Id;

	// Operations
	inline T op(T a, T b) {
		return max(a, b);
	}
	inline node merge(node a, node b) {
		node ans;
		ans.val = op(a.val, b.val);
		return ans;
	}

	// Private Functions
	void build(int nd, int s, int e) {
		if(s == e) {
            tr[nd].val = {0, -s};
            return;
		}
		int m = (s + e) >> 1;
		build(nd << 1, s, m);
		build(nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	void upd(int idx, int x, int nd, int s, int e) {
		if(s == e) {
    		tr[nd].val.fi += x; return;
		}
		int m = (s + e) >> 1;
		if(idx <= m)
			upd(idx, x, nd << 1, s, m);
		else
			upd(idx, x, nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	T query(int l, int r, int nd, int s, int e) {
		if(s > r || e < l) return Id;
		if(l <= s && e <= r) return tr[nd].val;
		int m = (s + e) >> 1;
		return op(query(l, r, nd << 1, s, m), query(l, r, nd << 1 | 1, m + 1, e));
	}

	void print(int l,int r,int nd,int s,int e, vector<T> &v) {
		if(s > r || e < l) return;
		if(s == e) {
			v.push_back(tr[nd].val);
			return;
		}
		int m = (s + e) >> 1;
		print(l, r, nd << 1, s, m, v);
		print(l, r, nd << 1 | 1, m + 1, e, v);
	}

public:
	// Constructor
	Segtree_Without_Lazy(int nn) : n(nn), Id({0, -1e9}), tr(4 * nn) {
        build(1, 1, nn);
    }

	// Functions
	void upd(int idx, int val) {
		upd(idx, val, 1, 1, n);
	}

	T query(int l,int r) {
		if(l > r) return Id;
		return query(l, r, 1, 1, n);
	}

	void print(int l,int r) {
		vector<T> v;
		print(l, r, 1, 1, n, v);
		debug(v);
	}
};

vector<int> g[2 * MAXLEN];

Segtree_Without_Lazy<pii> seg(5e4 + 5);

const int LOGN = 20;
const int N = MAXLEN;
int dp[LOGN][N];
int S[N];

pii ans[N];
int str[N], en[N], ver[N], tt;

void pre(int u, int p) {
    str[u] = ++tt;
    ver[tt] = u;
    S[u] = 1;
    dp[0][u] = p;
    for(int v : g[u]) {
        pre(v, u);
        S[u] += S[v];
    }
    en[u] = tt;
}

int go(int u, int l) {
    for(int k = LOGN - 1; k >= 0; k--) {
        if(dp[k][u] && st[dp[k][u]].len >= l) u = dp[k][u];
    }
    return u;
}

vector<tuple<int,int,int>> queries[N];

void dfs(int v, int p, bool keep){
    int mx = -1, bigChild = -1;
    for(auto u : g[v])
       if(S[u] > mx)
          mx = S[u], bigChild = u;
    for(auto u : g[v])
        if(u != bigChild)
            dfs(u, v, 0);
    if(bigChild != -1) dfs(bigChild, v, 1);
    for(auto u : g[v])
        if(u != bigChild)
            for(int p = str[u]; p <= en[u]; p++)
                if(id[ver[p]])
                    seg.upd(id[ver[p]], 1);
    if(id[v])
        seg.upd(id[v], 1);
    for(auto x : queries[v]) {
        int l = get<0>(x), r = get<1>(x), idx = get<2>(x);
        ans[idx] = seg.query(l, r);
    }
    if(!keep)
        for(int p = str[v]; p <= en[v]; p++)
            if(id[ver[p]])
	            seg.upd(id[ver[p]], -1);
}

void solve() {
	string s;
    sc(s);
    sa_init();
    int pc = 0;
    string tot = "";
    fr(i, 0, sz(s) - 1) {
        sa_extend(s[i], 0, pc++);
        tot += s[i];
    }
    int m;
    sc(m);
    fr(i, 1, m) {
        string p;
        sc(p);
        sa_extend('#', 0, pc++);
        tot += '#';
        for(char ch : p) {
            sa_extend(ch, i, pc++);
            tot += ch;
        }
    }
    fr(i, 2, sz - 1) {
        g[st[i].link].pb(i);
    }
    pre(1, 0);
    fr(k, 1, LOGN - 1) {
        fr(i, 1, sz - 1) {
            dp[k][i] = dp[k - 1][dp[k - 1][i]];
        }
    }
    int q;
    sc(q);
    fr(i, 1, q) {
        int l, r, pl, pr;
        sc(l, r, pl, pr);
        int u = gn[pr - 1];
        int v = go(u, pr - pl + 1);
        queries[v].eb(l, r, i);
    }
    dfs(1, 0, 1);
    fr(i, 1, q) {
        cout << -ans[i].se << " " << ans[i].fi << endl;
    }
}

int main() {
	ios :: sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin >> t;
	for(int tt = 1; tt <= t; tt++) {
		solve();
	}
	return 0;
}


#include "bits/stdc++.h"
using namespace std;
#ifndef LOCAL
#define endl '\n'
#endif

#define fr(i, a, b) for(int i = a; i <= b; i++)
#define rf(i, a, b) for(int i = a; i >= b; i--)
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define sz(x) (int)x.size()
#define lb lower_bound
#define ub upper_bound

typedef long long ll;
typedef long double f80;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;

int pct(int x) { return __builtin_popcount(x); }
int pct(ll x) { return __builtin_popcountll(x); }
int bt(int x) { return 31 - __builtin_clz(x); } // floor(log2(x))
int bt(ll x) { return 63 - __builtin_clzll(x); } // floor(log2(x))
int cdiv(int a, int b) { return a / b + !(a < 0 || a % b == 0); }
ll cdiv(ll a, ll b) { return a / b + !(a < 0 || a % b == 0); }
int nxt_C(int x) { int c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }
ll nxt_C(ll x) { ll c = x & -x, r = x + c; return (((r ^ x) >> 2) / c) | r; }

vector<int> get_bits(int mask) {
	vector<int> bb;
	while(mask) { int b = bt(mask); bb.pb(b); mask ^= (1 << b); }
	reverse(all(bb));
	return bb;
}

int get_mask(vector<int> v) {
	int mask = 0;
	for(int x : v) { mask ^= (1 << x); }
	return mask;
}

template<typename T>
void uniq(vector<T> &v) { sort(all(v)); v.resize(unique(all(v)) - v.begin()); }
// template<typename T>
// void leftShift(vector<T> &v, ll k) { k %= sz(v); if(k < 0) k += sz(v); rotate(v.begin(), v.begin() + k, v.end()); }
// template<typename T>
// void rightShift(vector<T> &v, ll k) { leftShift(v, sz(v) - k); }

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

ll rand(ll l, ll r){
	uniform_int_distribution<ll> uid(l, r);
	return uid(rng);
}

void sc() {}

template <typename Head, typename... Tail>
void sc(Head &H, Tail &... T) { cin >> H; sc(T...); }

#ifdef LOCAL
#define debug(...) cerr << "[L:" << __LINE__ << "][" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

// #ifndef LOCAL
// string to_string(__int128 x) {
// 	string s = "";
// 	bool neg = 0;
// 	if(x < 0) { s += "-"; neg = 1; x = -x; }
// 	if(!x) s += '0';
// 	while(x) {
// 		int rem = x % 10;
// 		s += to_string(rem);
// 		x /= 10;
// 	}
// 	reverse(s.begin() + neg, s.end());
// 	return s;
// }
// #endif

const int mod = 1e9 + 7; // 998244353;

int pwr(int a,ll b) {
	int ans = 1;
	while(b) {
		if(b & 1) ans = (ans * 1LL * a) % mod;
		a = (a * 1LL * a) % mod;
		b >>= 1;
	}
	return ans;
}

/*
	Lookout for overflows!!
	Check array sizes!!
	Clear before test cases!!
	Use the correct modulo!!
	Check for corner cases!!
	Are you forgetting something?!
	Read problem statement carefully!!!
*/

struct state {
    int len, link;
    map<char, int> next;
};
const int MAXLEN = 6e5 + 5;

int cnt[2 * MAXLEN];
int id[2 * MAXLEN];
int gn[MAXLEN];

state st[MAXLEN * 2];
int sz = 1, last;
void sa_init() {
    st[1].len = 0;
    st[1].link = -1;
    sz++;
    last = 1;
}
void sa_extend(char c, int idx, int pos) {
    int cur = sz++;
    st[cur].len = st[last].len + 1;
    int p = last;
    while (p != -1 && !st[p].next.count(c)) {
        st[p].next[c] = cur;
        p = st[p].link;
    }
    if (p == -1) {
        st[cur].link = 1;
    } else {
        int q = st[p].next[c];
        if (st[p].len + 1 == st[q].len) {
            st[cur].link = q;
        } else {
            int clone = sz++;
            st[clone].len = st[p].len + 1;
            st[clone].next = st[q].next;
            st[clone].link = st[q].link;
            while (p != -1 && st[p].next[c] == q) {
                st[p].next[c] = clone;
                p = st[p].link;
            }
            st[q].link = st[cur].link = clone;
        }
    }
    last = cur;
    id[cur] = idx;
    gn[pos] = cur;
}

/*
	Fill all the ...
	Set the Identity element.
	Set the template variable type carefully.
*/
template<typename T>
class Segtree_Without_Lazy {
	struct node {
		T val;
	};

	// Variables
	int n;
	vector<node> tr;
	T Id;

	// Operations
	inline T op(T a, T b) {
		return max(a, b);
	}
	inline node merge(node a, node b) {
		node ans;
		ans.val = op(a.val, b.val);
		return ans;
	}

	// Private Functions
	void build(int nd, int s, int e) {
		if(s == e) {
            tr[nd].val = {0, s};
            return;
		}
		int m = (s + e) >> 1;
		build(nd << 1, s, m);
		build(nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	void upd(int idx, int x, int nd, int s, int e) {
		if(s == e) {
    		tr[nd].val.fi += x; return;
		}
		int m = (s + e) >> 1;
		if(idx <= m)
			upd(idx, x, nd << 1, s, m);
		else
			upd(idx, x, nd << 1 | 1, m + 1, e);
		tr[nd] = merge(tr[nd << 1], tr[nd << 1 | 1]);
	}

	T query(int l, int r, int nd, int s, int e) {
		if(s > r || e < l) return Id;
		if(l <= s && e <= r) return tr[nd].val;
		int m = (s + e) >> 1;
		return op(query(l, r, nd << 1, s, m), query(l, r, nd << 1 | 1, m + 1, e));
	}

	void print(int l,int r,int nd,int s,int e, vector<T> &v) {
		if(s > r || e < l) return;
		if(s == e) {
			v.push_back(tr[nd].val);
			return;
		}
		int m = (s + e) >> 1;
		print(l, r, nd << 1, s, m, v);
		print(l, r, nd << 1 | 1, m + 1, e, v);
	}

public:
	// Constructor
	Segtree_Without_Lazy(int nn) : n(nn), Id({0, 0}), tr(4 * nn) {
        build(1, 1, nn);
    }

	// Functions
	void upd(int idx, int val) {
		upd(idx, val, 1, 1, n);
	}

	T query(int l,int r) {
		if(l > r) return Id;
		return query(l, r, 1, 1, n);
	}

	void print(int l,int r) {
		vector<T> v;
		print(l, r, 1, 1, n, v);
		debug(v);
	}
};

vector<int> g[2 * MAXLEN];

Segtree_Without_Lazy<pii> seg(5e4 + 5);

const int LOGN = 20;
const int N = MAXLEN;
int dp[LOGN][N];
int S[N];

pii ans[N];
int str[N], en[N], ver[N], tt;

void pre(int u, int p) {
    str[u] = ++tt;
    ver[tt] = u;
    S[u] = 1;
    dp[0][u] = p;
    for(int v : g[u]) {
        pre(v, u);
        S[u] += S[v];
    }
    en[u] = tt;
}

int go(int u, int l) {
    for(int k = LOGN - 1; k >= 0; k--) {
        if(dp[k][u] && st[dp[k][u]].len >= l) u = dp[k][u];
    }
    return u;
}

vector<tuple<int,int,int>> queries[N];

void dfs(int v, int p, bool keep){
    int mx = -1, bigChild = -1;
    for(auto u : g[v])
       if(S[u] > mx)
          mx = S[u], bigChild = u;
    for(auto u : g[v])
        if(u != bigChild)
            dfs(u, v, 0);
    if(bigChild != -1) dfs(bigChild, v, 1);
    for(auto u : g[v])
        if(u != bigChild)
            for(int p = str[u]; p <= en[u]; p++)
                if(id[ver[p]])
                    seg.upd(id[ver[p]], 1);
    if(id[v])
        seg.upd(id[v], 1);
    for(auto x : queries[v]) {
        int l = get<0>(x), r = get<1>(x), idx = get<2>(x);
        ans[idx] = seg.query(l, r);
    }
    if(!keep)
        for(int p = str[v]; p <= en[v]; p++)
            if(id[ver[p]])
	            seg.upd(id[ver[p]], -1);
}

void solve() {
	string s;
    sc(s);
    sa_init();
    int pc = 0;
    string tot = "";
    fr(i, 0, sz(s) - 1) {
        sa_extend(s[i], 0, pc++);
        tot += s[i];
    }
    int m;
    sc(m);
    fr(i, 1, m) {
        string p;
        sc(p);
        sa_extend('#', 0, pc++);
        tot += '#';
        for(char ch : p) {
            sa_extend(ch, i, pc++);
            tot += ch;
        }
    }
    fr(i, 2, sz - 1) {
        g[st[i].link].pb(i);
    }
    pre(1, 0);
    fr(k, 1, LOGN - 1) {
        fr(i, 1, sz - 1) {
            dp[k][i] = dp[k - 1][dp[k - 1][i]];
        }
    }
    int q;
    sc(q);
    fr(i, 1, q) {
        int l, r, pl, pr;
        sc(l, r, pl, pr);
        int u = gn[pr - 1];
        int v = go(u, pr - pl + 1);
        queries[v].eb(l, r, i);
    }
    dfs(1, 0, 1);
    fr(i, 1, q) {
        cout << ans[i].se << " " << ans[i].fi << endl;
    }
}

int main() {
	ios :: sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t = 1;
	// cin >> t;
	for(int tt = 1; tt <= t; tt++) {
		solve();
	}
	return 0;
}