Problem: Owl Sonya gave a huge lake puzzle of size n × m to hedgehog Filya as a birthday present. Friends immediately started to assemble the puzzle, but some parts of it turned out to be empty — there was no picture on them. Parts with picture on it are denoted by 1, while empty parts are denoted by 0. Rows of the puzzle are numbered from top to bottom with integers from 1 to n, while columns are numbered from left to right with integers from 1 to m.

Animals decided to complete the picture and play with it, as it might be even more fun! Owl and hedgehog ask each other some queries. Each query is provided by four integers x1, y1, x2, y2 which define the rectangle, where (x1, y1) stands for the coordinates of the up left cell of the rectangle, while (x2, y2) stands for the coordinates of the bottom right cell. The answer to the query is the size of the maximum square consisting of picture parts only (only parts denoted by 1) and located fully inside the query rectangle.

Help Sonya and Filya answer t queries.

Input

The first line of the input contains two integers n and m (1 ≤ n, m ≤ 1000) — sizes of the puzzle.

Each of the following n lines contains m integers aij. Each of them is equal to 1 if the corresponding cell contains a picture and 0 if it's empty.

Next line contains an integer t (1 ≤ t ≤ 1 000 000) — the number of queries.

Then follow t lines with queries' descriptions. Each of them contains four integers x1, y1, x2, y2 (1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m) — coordinates of the up left and bottom right cells of the query rectangle.

Output

Print t lines. The i-th of them should contain the maximum size of the square consisting of 1-s and lying fully inside the query rectangle.

Example

Input

3 4
1 1 0 1
0 1 1 0
0 1 1 0
5
1 1 2 3
2 1 3 2
3 2 3 4
1 1 3 4
1 2 3 4


Output

1
1
1
2
2

Solution (in JAVA):

Solution:
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Closeable;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 29);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            DAnimalsAndPuzzle solver = new DAnimalsAndPuzzle();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class DAnimalsAndPuzzle {
        IntegerSparseTable2D st;

        public void solve(int testNumber, FastInput in, FastOutput out) {
            int n = in.readInt();
            int m = in.readInt();
            int[][] mat = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    mat[i][j] = in.readInt();
                }
            }
            int[][] square = new int[n][m];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    if (i == 0 || j == 0) {
                        square[i][j] = mat[i][j];
                        continue;
                    }
                    if (mat[i][j] == 0) {
                        continue;
                    }
                    square[i][j] = 1 + Math.min(Math.min(square[i][j - 1], square[i - 1][j]), square[i - 1][j - 1]);
                }
            }

            st = new IntegerSparseTable2D((i, j) -> square[i][j], n, m, Math::max);
            int q = in.readInt();
            for (int i = 0; i < q; i++) {
                int b = in.readInt() - 1;
                int l = in.readInt() - 1;
                int t = in.readInt() - 1;
                int r = in.readInt() - 1;

                int lo = 0;
                int hi = n;
                while (lo < hi) {
                    int mid = (lo + hi + 1) / 2;
                    if (check(b, t, l, r, mid)) {
                        lo = mid;
                    } else {
                        hi = mid - 1;
                    }
                }

                out.println(lo);
            }
        }

        public boolean check(int b, int t, int l, int r, int mid) {
            if (mid == 0) {
                return true;
            }
            b += mid - 1;
            l += mid - 1;
            if (b > t || l > r) {
                return false;
            }
            return st.query(b, t, l, r) >= mid;
        }

    }

    static interface IntegerBinaryFunction {
        int apply(int a, int b);

    }

    static class IntegerSparseTable2D {
        private ArrayIndex ai;
        private int[] data;
        private IntegerBinaryFunction merger;

        public IntegerSparseTable2D(Int2ToIntegerFunction mat, int n, int m, IntegerBinaryFunction merger) {
            this.merger = merger;
            int logn = Log2.floorLog(n);
            int logm = Log2.floorLog(m);
            ai = new ArrayIndex(logn + 1, n, logm + 1, m);
            data = new int[ai.totalSize()];


            for (int i = 0; i <= logn; i++) {
                for (int j = 0; j < n; j++) {
                    for (int k = 0; k <= logm; k++) {
                        for (int t = 0; t < m; t++) {
                            if (i == 0 && k == 0) {
                                data[ai.indexOf(i, j, k, t)] = mat.apply(j, t);
                            } else if (i == 0) {
                                data[ai.indexOf(i, j, k, t)] = merger.apply(
                                        data[ai.indexOf(i, j, k - 1, t)],
                                        data[ai.indexOf(i, j, k - 1, Math.min(t + (1 << k - 1), m - 1))]
                                );
                            } else if (k == 0) {
                                data[ai.indexOf(i, j, k, t)] = merger.apply(
                                        data[ai.indexOf(i - 1, j, k, t)],
                                        data[ai.indexOf(i - 1, Math.min(j + (1 << i - 1), n - 1), k, t)]
                                );
                            } else {
                                int ans = merger.apply(data[ai.indexOf(i - 1, j, k, t)],
                                        data[ai.indexOf(i - 1, Math.min(j + (1 << i - 1), n - 1), k, t)]);
                                ans = merger.apply(data[ai.indexOf(i - 1, j, k - 1, Math.min(t + (1 << k - 1), m - 1))], ans);
                                ans = merger.apply(data[ai.indexOf(i - 1, Math.min(j + (1 << i - 1), n - 1), k - 1, Math.min(t + (1 << k - 1), m - 1))], ans);
                                data[ai.indexOf(i, j, k, t)] = ans;
                            }
                        }
                    }
                }
            }
        }

        public int query(int b, int t, int l, int r) {
            int h = t - b + 1;
            int w = r - l + 1;
            int logh = Log2.floorLog(h);
            int logw = Log2.floorLog(w);

            int ans = merger.apply(data[ai.indexOf(logh, b, logw, l)],
                    data[ai.indexOf(logh, t + 1 - (1 << logh), logw, l)]);
            ans = merger.apply(data[ai.indexOf(logh, b, logw, r + 1 - (1 << logw))], ans);
            ans = merger.apply(data[ai.indexOf(logh, t + 1 - (1 << logh), logw, r + 1 - (1 << logw))], ans);
            return ans;
        }

    }

    static interface Int2ToIntegerFunction {
        int apply(int a, int b);

    }

    static class FastOutput implements AutoCloseable, Closeable, Appendable {
        private StringBuilder cache = new StringBuilder(10 << 20);
        private final Writer os;

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput println(int c) {
            return append(c).println();
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class Log2 {
        public static int floorLog(int x) {
            return 31 - Integer.numberOfLeadingZeros(x);
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class ArrayIndex {
        int[] dimensions;

        public ArrayIndex(int... dimensions) {
            this.dimensions = dimensions;
        }

        public int totalSize() {
            int ans = 1;
            for (int x : dimensions) {
                ans *= x;
            }
            return ans;
        }

        public int indexOf(int a, int b, int c, int d) {
            return ((a * dimensions[1] + b) * dimensions[2] + c) * dimensions[3] + d;
        }

    }
}