import java.io.*;
import static java.lang.Math.*;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.*;
import java.lang.*;

public class Main {
    final static boolean debug = false;
    final static String fileName = "";
    final static boolean useFiles = false;

    public static void main(String[] args) throws FileNotFoundException {
        long start;
        if (debug)
            start = System.nanoTime();
        InputStream inputStream;
        OutputStream outputStream;
        if (useFiles) {
            inputStream = new FileInputStream(fileName + ".in");
            outputStream = new FileOutputStream(fileName + ".out");
        } else {
            inputStream = System.in;
            outputStream = System.out;
        }
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        Task solver = new Task(in, out);
        solver.solve();
        if(debug)
            out.println((System.nanoTime() - start) / 1e+9);
        out.close();
    }
}

class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream), 32768);
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

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

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

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

    public byte nextByte(){
        return Byte.parseByte(next());
    }
}

class P{
    char A, B;
    P(char a, char b){
        if (a < b){
            A = a;
            B = b;
        }
        else{
            A = b;
            B = a;
        }
    }
    boolean equals(P r){
        return r.A == A && r.B == B;
    }
}

class Rook{
    int X, Y;
    Rook(int x, int y){
        X = x;
        Y = y;
    }
}

class Query{
    int X1, X2, Y1, Y2;
    int Id;
    Query(int x1, int y1, int x2, int y2, int id){
        X1 = x1;
        X2 = x2;
        Y1 = y1;
        Y2 = y2;
        Id = id;
    }
}

class Task {
    public void solve() {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();
        int q = in.nextInt();
        Rook[] rooks = new Rook[k];
        for (int i = 0; i < k; i++) {
            rooks[i] = new Rook(in.nextInt() - 1, in.nextInt() - 1);
        }
        Query[] queries = new Query[q];
        for (int i = 0; i < q; i++) {
            queries[i] = new Query(in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, i);
        }
        boolean[] x = doIt(n, m, queries, rooks);
        for (Rook rook : rooks) {
            int t = rook.X;
            rook.X = rook.Y;
            rook.Y = t;
        }
        for (Query query : queries) {
            int t = query.X1;
            query.X1 = query.Y1;
            query.Y1 = t;

            t = query.X2;
            query.X2 = query.Y2;
            query.Y2 = t;
        }
        boolean[] y = doIt(n, m, queries, rooks);
        for (int i = 0; i < rooks.length; i++) {
            out.println(x[i] || y[i] ? "YES" : "NO");
        }
    }

    boolean[] doIt(int n, int m, Query[] queries, Rook[] rooks) {
        ArrayList<Query>[] queriesByY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            queriesByY[i] = new ArrayList<>();
        }
        for (Query query : queries) {
            queriesByY[query.Y1].add(query);
        }

        int[] position = new int[n];
        ArrayList<Rook>[] byX = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            byX[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byX[rook.X].add(rook);
        }
        for (int x = 0; x < n; x++) {
            Collections.sort(byX[x], new Comparator<Rook>() {
                @Override
                public int compare(Rook o1, Rook o2) {
                    return o1.Y - o2.Y;
                }
            });
        }

        ArrayList<Rook>[] byY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            byY[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byY[rook.Y].add(rook);
        }
        boolean[] result = new boolean[queries.length];
        BinaryOperatorSegmentTree tree = new BinaryOperatorSegmentTree(n, Math::max);
        for (int x = 0; x < n; x++) {
            if (byX[x].size() == 0) {
                tree.set(x, m);
            } else {
                tree.set(x, byX[x].get(0).Y);
            }
        }
        for (int y = 0; y < m; y++) {
            for (Query q : queriesByY[y]) {
                result[q.Id] = tree.get(q.X1, q.X2) <= q.Y2;
            }
            for (Rook rook : byY[y]) {
                if (position[rook.X] >= byX[rook.X].size() - 1)
                    tree.set(rook.X, m);
                else {
                    position[rook.X]++;
                    tree.set(rook.X, byX[rook.X].get(position[rook.X]).Y);
                }
            }
        }
        return result;
    }

    private InputReader in;
    private PrintWriter out;

    Task(InputReader in, PrintWriter out) {
        this.in = in;
        this.out = out;
    }
}


import java.io.*;
import static java.lang.Math.*;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.*;
import java.lang.*;

public class Main {
    final static boolean debug = false;
    final static String fileName = "";
    final static boolean useFiles = false;

    public static void main(String[] args) throws FileNotFoundException {
        long start;
        if (debug)
            start = System.nanoTime();
        InputStream inputStream;
        OutputStream outputStream;
        if (useFiles) {
            inputStream = new FileInputStream(fileName + ".in");
            outputStream = new FileOutputStream(fileName + ".out");
        } else {
            inputStream = System.in;
            outputStream = System.out;
        }
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        Task solver = new Task(in, out);
        solver.solve();
        if(debug)
            out.println((System.nanoTime() - start) / 1e+9);
        out.close();
    }
}

class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream), 32768);
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

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

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

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

    public byte nextByte(){
        return Byte.parseByte(next());
    }
}

class P{
    char A, B;
    P(char a, char b){
        if (a < b){
            A = a;
            B = b;
        }
        else{
            A = b;
            B = a;
        }
    }
    boolean equals(P r){
        return r.A == A && r.B == B;
    }
}

class Rook{
    int X, Y;
    Rook(int x, int y){
        X = x;
        Y = y;
    }
}

class Query{
    int X1, X2, Y1, Y2;
    int Id;
    Query(int x1, int y1, int x2, int y2, int id){
        X1 = x1;
        X2 = x2;
        Y1 = y1;
        Y2 = y2;
        Id = id;
    }
}

class Task {
    public void solve() {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();
        int q = in.nextInt();
        Rook[] rooks = new Rook[k];
        for (int i = 0; i < k; i++) {
            rooks[i] = new Rook(in.nextInt() - 1, in.nextInt() - 1);
        }
        Query[] queries = new Query[q];
        for (int i = 0; i < q; i++) {
            queries[i] = new Query(in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, i);
        }
        boolean[] x = doIt(n, m, queries, rooks);
        for (Rook rook : rooks) {
            int t = rook.X;
            rook.X = rook.Y;
            rook.Y = t;
        }
        for (Query query : queries) {
            int t = query.X1;
            query.X1 = query.Y1;
            query.Y1 = t;

            t = query.X2;
            query.X2 = query.Y2;
            query.Y2 = t;
        }
        boolean[] y = doIt(m, n, queries, rooks);
        for (int i = 0; i < queries.length; i++) {
            out.println(x[i] || y[i] ? "YES" : "NO");
        }
    }

    boolean[] doIt(int n, int m, Query[] queries, Rook[] rooks) {
        ArrayList<Query>[] queriesByY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            queriesByY[i] = new ArrayList<>();
        }
        for (Query query : queries) {
            queriesByY[query.Y1].add(query);
        }

        int[] position = new int[n];
        ArrayList<Rook>[] byX = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            byX[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byX[rook.X].add(rook);
        }
        for (int x = 0; x < n; x++) {
            Collections.sort(byX[x], new Comparator<Rook>() {
                @Override
                public int compare(Rook o1, Rook o2) {
                    return o1.Y - o2.Y;
                }
            });
        }

        ArrayList<Rook>[] byY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            byY[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byY[rook.Y].add(rook);
        }
        boolean[] result = new boolean[queries.length];
        BinaryOperatorSegmentTree tree = new BinaryOperatorSegmentTree(n, Math::max);
        for (int x = 0; x < n; x++) {
            if (byX[x].size() == 0) {
                tree.set(x, m);
            } else {
                tree.set(x, byX[x].get(0).Y);
            }
        }
        for (int y = 0; y < m; y++) {
            for (Query q : queriesByY[y]) {
                result[q.Id] = tree.get(q.X1, q.X2) <= q.Y2;
            }
            for (Rook rook : byY[y]) {
                if (position[rook.X] >= byX[rook.X].size() - 1)
                    tree.set(rook.X, m);
                else {
                    position[rook.X]++;
                    tree.set(rook.X, byX[rook.X].get(position[rook.X]).Y);
                }
            }
        }
        return result;
    }

    private InputReader in;
    private PrintWriter out;

    Task(InputReader in, PrintWriter out) {
        this.in = in;
        this.out = out;
    }
}

class BinaryOperatorSegmentTree {
    private int[] t;
    private int n;
    private BinaryOperator<Integer> operator;

    BinaryOperatorSegmentTree(int n, BinaryOperator<Integer> operator) {
        this.n = n;
        t = new int[n << 2];
        this.operator = operator;
    }

    BinaryOperatorSegmentTree(int[] array, BinaryOperator<Integer> operator) {
        this(array.length, operator);
        build(0, 0, n - 1, array);
    }

    private void build(int v, int tl, int tr, int[] array) {
        if (tr == tl) {
            t[v] = array[tl];
        } else {
            int tm = (tl + tr) >> 1;
            build(2 * v + 1, tl, tm, array);
            build(2 * v + 2, tm + 1, tr, array);
            t[v] = operator.apply(t[2 * v + 1], t[2 * v + 2]);
        }
    }

    int get(int l, int r) {
        if (!(0 <= l && l < n && 0 <= r && r < n))
            throw new IllegalArgumentException("indices: (" + l + ", " + r + "). Bounds: (0, " + (n - 1) + ")");
        return get(0, 0, n - 1, l, r);
    }

    void set(int index, int value) {
        if (0 > index || index > n)
            throw new IllegalArgumentException("index: " + index + ". Bounds: " + (n - 1));
        set(0, 0, n - 1, index, value);
    }

    private int get(int v, int tl, int tr, int l, int r) {
        if (l > r)
            return 0;
        if (tl == l && tr == r)
            return t[v];
        int tm = (tl + tr) >> 1;
        return operator.apply(get(2 * v + 1, tl, tm, l, Math.min(tm, r)),
                get(2 * v + 2, tm + 1, tr, Math.max(tm + 1, l), r));
    }

    private void set(int v, int tl, int tr, int index, int value) {
        if (tr == tl)
            t[v] = operator.apply(value, t[v]);
        else {
            int tm = (tl + tr) >> 1;
            if (index <= tm)
                set(2 * v + 1, tl, tm, index, value);
            else
                set(2 * v + 2, tm + 1, tr, index, value);
            t[v] = operator.apply(t[2 * v + 1], t[2 * v + 2]);
        }
    }

    public int[] toArray() {
        int[] result = new int[n];
        for (int i = 0; i < n; i++)
            result[i] = get(i, i);
        return result;
    }

    @Override
    public String toString() {
        String result = "";
        for (int i = 0; i < n; i++)
            result += get(i, i) + " ";
        return result;
    }
}


import java.io.*;
import static java.lang.Math.*;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.function.*;
import java.lang.*;

public class Main {
    final static boolean debug = false;
    final static String fileName = "";
    final static boolean useFiles = false;

    public static void main(String[] args) throws FileNotFoundException {
        long start;
        if (debug)
            start = System.nanoTime();
        InputStream inputStream;
        OutputStream outputStream;
        if (useFiles) {
            inputStream = new FileInputStream(fileName + ".in");
            outputStream = new FileOutputStream(fileName + ".out");
        } else {
            inputStream = System.in;
            outputStream = System.out;
        }
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        Task solver = new Task(in, out);
        solver.solve();
        if(debug)
            out.println((System.nanoTime() - start) / 1e+9);
        out.close();
    }
}

class InputReader {
    public BufferedReader reader;
    public StringTokenizer tokenizer;

    public InputReader(InputStream stream) {
        reader = new BufferedReader(new InputStreamReader(stream), 32768);
        tokenizer = null;
    }

    public String next() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            try {
                tokenizer = new StringTokenizer(reader.readLine());
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return tokenizer.nextToken();
    }

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

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

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

    public byte nextByte(){
        return Byte.parseByte(next());
    }
}

class P{
    char A, B;
    P(char a, char b){
        if (a < b){
            A = a;
            B = b;
        }
        else{
            A = b;
            B = a;
        }
    }
    boolean equals(P r){
        return r.A == A && r.B == B;
    }
}

class Rook{
    int X, Y;
    Rook(int x, int y){
        X = x;
        Y = y;
    }
}

class Query{
    int X1, X2, Y1, Y2;
    int Id;
    Query(int x1, int y1, int x2, int y2, int id){
        X1 = x1;
        X2 = x2;
        Y1 = y1;
        Y2 = y2;
        Id = id;
    }
}

class Task {
    public void solve() {
        int n = in.nextInt();
        int m = in.nextInt();
        int k = in.nextInt();
        int q = in.nextInt();
        Rook[] rooks = new Rook[k];
        for (int i = 0; i < k; i++) {
            rooks[i] = new Rook(in.nextInt() - 1, in.nextInt() - 1);
        }
        Query[] queries = new Query[q];
        for (int i = 0; i < q; i++) {
            queries[i] = new Query(in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, in.nextInt() - 1, i);
        }
        boolean[] x = doIt(n, m, queries, rooks);
        for (Rook rook : rooks) {
            int t = rook.X;
            rook.X = rook.Y;
            rook.Y = t;
        }
        for (Query query : queries) {
            int t = query.X1;
            query.X1 = query.Y1;
            query.Y1 = t;

            t = query.X2;
            query.X2 = query.Y2;
            query.Y2 = t;
        }
        boolean[] y = doIt(n, m, queries, rooks);
        for (int i = 0; i < rooks.length; i++) {
            out.println(x[i] || y[i] ? "YES" : "NO");
        }
    }

    boolean[] doIt(int n, int m, Query[] queries, Rook[] rooks) {
        ArrayList<Query>[] queriesByY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            queriesByY[i] = new ArrayList<>();
        }
        for (Query query : queries) {
            queriesByY[query.Y1].add(query);
        }

        int[] position = new int[n];
        ArrayList<Rook>[] byX = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            byX[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byX[rook.X].add(rook);
        }
        for (int x = 0; x < n; x++) {
            Collections.sort(byX[x], new Comparator<Rook>() {
                @Override
                public int compare(Rook o1, Rook o2) {
                    return o1.Y - o2.Y;
                }
            });
        }

        ArrayList<Rook>[] byY = new ArrayList[m];
        for (int i = 0; i < m; i++) {
            byY[i] = new ArrayList<>();
        }
        for (Rook rook : rooks) {
            byY[rook.Y].add(rook);
        }
        boolean[] result = new boolean[queries.length];
        BinaryOperatorSegmentTree tree = new BinaryOperatorSegmentTree(n, Math::max);
        for (int x = 0; x < n; x++) {
            if (byX[x].size() == 0) {
                tree.set(x, m);
            } else {
                tree.set(x, byX[x].get(0).Y);
            }
        }
        for (int y = 0; y < m; y++) {
            for (Query q : queriesByY[y]) {
                result[q.Id] = tree.get(q.X1, q.X2) <= q.Y2;
            }
            for (Rook rook : byY[y]) {
                if (position[rook.X] >= byX[rook.X].size() - 1)
                    tree.set(rook.X, m);
                else {
                    position[rook.X]++;
                    tree.set(rook.X, byX[rook.X].get(position[rook.X]).Y);
                }
            }
        }
        return result;
    }

    private InputReader in;
    private PrintWriter out;

    Task(InputReader in, PrintWriter out) {
        this.in = in;
        this.out = out;
    }
}

class BinaryOperatorSegmentTree {
    private int[] t;
    private int n;
    private BinaryOperator<Integer> operator;

    BinaryOperatorSegmentTree(int n, BinaryOperator<Integer> operator) {
        this.n = n;
        t = new int[n << 2];
        this.operator = operator;
    }

    BinaryOperatorSegmentTree(int[] array, BinaryOperator<Integer> operator) {
        this(array.length, operator);
        build(0, 0, n - 1, array);
    }

    private void build(int v, int tl, int tr, int[] array) {
        if (tr == tl) {
            t[v] = array[tl];
        } else {
            int tm = (tl + tr) >> 1;
            build(2 * v + 1, tl, tm, array);
            build(2 * v + 2, tm + 1, tr, array);
            t[v] = operator.apply(t[2 * v + 1], t[2 * v + 2]);
        }
    }

    int get(int l, int r) {
        if (l > n || r > n || 0 > l || 0 > r)
            throw new IllegalArgumentException("indices: (" + l + ", " + r + ") . Bounds: (0, "+ (n - 1));
        return get(0, 0, n - 1, l, r);
    }

    void set(int index, int value) {
        if (0 > index || index > n)
            throw new IllegalArgumentException("index: " + index + ". Bounds: " + (n - 1));
        set(0, 0, n - 1, index, value);
    }

    private int get(int v, int tl, int tr, int l, int r) {
        if (l > r)
            return 0;
        if (tl == l && tr == r)
            return t[v];
        int tm = (tl + tr) >> 1;
        return operator.apply(get(2 * v + 1, tl, tm, l, Math.min(tm, r)),
                get(2 * v + 2, tm + 1, tr, Math.max(tm + 1, l), r));
    }

    private void set(int v, int tl, int tr, int index, int value) {
        if (tr == tl)
            t[v] = operator.apply(value, t[v]);
        else {
            int tm = (tl + tr) >> 1;
            if (index <= tm)
                set(2 * v + 1, tl, tm, index, value);
            else
                set(2 * v + 2, tm + 1, tr, index, value);
            t[v] = operator.apply(t[2 * v + 1], t[2 * v + 2]);
        }
    }

    public int[] toArray() {
        int[] result = new int[n];
        for (int i = 0; i < n; i++)
            result[i] = get(i, i);
        return result;
    }

    @Override
    public String toString() {
        String result = "";
        for (int i = 0; i < n; i++)
            result += get(i, i) + " ";
        return result;
    }
}


import java.util.*;
import java.io.*;
import java.awt.Point;
import java.math.BigDecimal;
import java.math.BigInteger;

import static java.lang.Math.*;

// Solution is at the bottom of code

public class E implements Runnable{

	final boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null;

	BufferedReader in;
	OutputWriter out;
	StringTokenizer tok = new StringTokenizer("");

	public static void main(String[] args){
		new Thread(null, new E(), "", 128 * (1L << 20)).start();
	}

	/////////////////////////////////////////////////////////////////////

	void init() throws FileNotFoundException{
		Locale.setDefault(Locale.US);

		if (ONLINE_JUDGE){
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new OutputWriter(System.out);
		}else{
			in = new BufferedReader(new FileReader("input.txt"));
			out = new OutputWriter("output.txt");
		}
	}

	////////////////////////////////////////////////////////////////

	long timeBegin, timeEnd;

	void time(){
		timeEnd = System.currentTimeMillis();
		System.err.println("Time = " + (timeEnd - timeBegin));
	}

	void debug(Object... objects){
		if (ONLINE_JUDGE){
			for (Object o: objects){
				System.err.println(o.toString());
			}
		}
	}

	/////////////////////////////////////////////////////////////////////

	public void run(){
		try{
			timeBegin = System.currentTimeMillis();
			Locale.setDefault(Locale.US);

			init();
			solve();

			out.close();
			time();
		}catch (Exception e){
			e.printStackTrace(System.err);
			System.exit(-1);
		}
	}

	/////////////////////////////////////////////////////////////////////

	String delim = " ";

	String readString() throws IOException{
		while(!tok.hasMoreTokens()){
			try{
				tok = new StringTokenizer(in.readLine());
			}catch (Exception e){
				return null;
			}
		}

		return tok.nextToken(delim);
	}

	String readLine() throws IOException{
		return in.readLine();
	}

	/////////////////////////////////////////////////////////////////

	final char NOT_A_SYMBOL = '\0';

	char readChar() throws IOException{
		int intValue = in.read();

		if (intValue == -1){
			return NOT_A_SYMBOL;
		}

		return (char) intValue;
	}

	char[] readCharArray() throws IOException{
		return readLine().toCharArray();
	}

	/////////////////////////////////////////////////////////////////

	int readInt() throws IOException {
		return Integer.parseInt(readString());
	}

	int[] readIntArray(int size) throws IOException {
		int[] array = new int[size];

		for (int index = 0; index < size; ++index){
			array[index] = readInt();
		}

		return array;
	}

	int[] readSortedIntArray(int size) throws IOException {
		Integer[] array = new Integer[size];

		for (int index = 0; index < size; ++index) {
			array[index] = readInt();
		}
		Arrays.sort(array);

		int[] sortedArray = new int[size];
		for (int index = 0; index < size; ++index) {
			sortedArray[index] = array[index];
		}

		return sortedArray;
	}

	int[] readIntArrayWithDecrease(int size) throws IOException {
		int[] array = readIntArray(size);

		for (int i = 0; i < size; ++i) {
			array[i]--;
		}

		return array;
	}

	///////////////////////////////////////////////////////////////////

	int[][] readIntMatrix(int rowsCount, int columnsCount) throws IOException {
		int[][] matrix = new int[rowsCount][];

		for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
			matrix[rowIndex] = readIntArray(columnsCount);
		}

		return matrix;
	}

	int[][] readIntMatrixWithDecrease(int rowsCount, int columnsCount) throws IOException {
		int[][] matrix = new int[rowsCount][];

		for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
			matrix[rowIndex] = readIntArrayWithDecrease(columnsCount);
		}

		return matrix;
	}

	///////////////////////////////////////////////////////////////////

	long readLong() throws IOException{
		return Long.parseLong(readString());
	}

	long[] readLongArray(int size) throws IOException{
		long[] array = new long[size];

		for (int index = 0; index < size; ++index){
			array[index] = readLong();
		}

		return array;
	}

	////////////////////////////////////////////////////////////////////

	double readDouble() throws IOException{
		return Double.parseDouble(readString());
	}

	double[] readDoubleArray(int size) throws IOException{
		double[] array = new double[size];

		for (int index = 0; index < size; ++index){
			array[index] = readDouble();
		}

		return array;
	}

	////////////////////////////////////////////////////////////////////

	BigInteger readBigInteger() throws IOException {
		return new BigInteger(readString());
	}

	BigDecimal readBigDecimal() throws IOException {
		return new BigDecimal(readString());
	}

	/////////////////////////////////////////////////////////////////////

	Point readPoint() throws IOException{
		int x = readInt();
		int y = readInt();
		return new Point(x, y);
	}

	Point[] readPointArray(int size) throws IOException{
		Point[] array = new Point[size];

		for (int index = 0; index < size; ++index){
			array[index] = readPoint();
		}

		return array;
	}

	/////////////////////////////////////////////////////////////////////

	List<Integer>[] readGraph(int vertexNumber, int edgeNumber)
	throws IOException{
		@SuppressWarnings("unchecked")
		List<Integer>[] graph = new List[vertexNumber];

		for (int index = 0; index < vertexNumber; ++index){
			graph[index] = new ArrayList<Integer>();
		}

		while (edgeNumber-- > 0){
			int from = readInt() - 1;
			int to = readInt() - 1;

			graph[from].add(to);
			graph[to].add(from);
		}

		return graph;
	}

	/////////////////////////////////////////////////////////////////////

	static class IntIndexPair {

		static Comparator<IntIndexPair> increaseComparator = new Comparator<E.IntIndexPair>() {

			@Override
			public int compare(IntIndexPair indexPair1, IntIndexPair indexPair2) {
				int value1 = indexPair1.value;
				int value2 = indexPair2.value;

				if (value1 != value2) return value1 - value2;

				int index1 = indexPair1.index;
				int index2 = indexPair2.index;

				return index1 - index2;
			}
		};

		static Comparator<IntIndexPair> decreaseComparator = new Comparator<E.IntIndexPair>() {

			@Override
			public int compare(IntIndexPair indexPair1, IntIndexPair indexPair2) {
				int value1 = indexPair1.value;
				int value2 = indexPair2.value;

				if (value1 != value2) return -(value1 - value2);

				int index1 = indexPair1.index;
				int index2 = indexPair2.index;

				return index1 - index2;
			}
		};

		int value, index;

		public IntIndexPair(int value, int index) {
			super();
			this.value = value;
			this.index = index;
		}

		public int getRealIndex() {
			return index + 1;
		}
	}

	IntIndexPair[] readIntIndexArray(int size) throws IOException {
		IntIndexPair[] array = new IntIndexPair[size];

		for (int index = 0; index < size; ++index) {
			array[index] = new IntIndexPair(readInt(), index);
		}

		return array;
	}

	/////////////////////////////////////////////////////////////////////

	static class OutputWriter extends PrintWriter {

		final int DEFAULT_PRECISION = 12;

		protected int precision;
		protected String format, formatWithSpace;

		{
			precision = DEFAULT_PRECISION;

			format = createFormat(precision);
			formatWithSpace = format + " ";
		}

		public OutputWriter(OutputStream out) {
			super(out);
		}

		public OutputWriter(String fileName) throws FileNotFoundException {
			super(fileName);
		}

		public int getPrecision() {
			return precision;
		}

		public void setPrecision(int precision) {
			precision = max(0, precision);
			this.precision = precision;

			format = createFormat(precision);
			formatWithSpace = format + " ";
		}

		private String createFormat(int precision){
			return "%." + precision + "f";
		}

		@Override
		public void print(double d){
			printf(format, d);
		}

		public void printWithSpace(double d){
			printf(formatWithSpace, d);
		}

		public void printAll(double...d){
			for (int i = 0; i < d.length - 1; ++i){
				printWithSpace(d[i]);
			}

			print(d[d.length - 1]);
		}

		@Override
		public void println(double d){
			printlnAll(d);
		}

		public void printlnAll(double... d){
			printAll(d);
			println();
		}
	}

	/////////////////////////////////////////////////////////////////////

	static final int[][] steps = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
	static final int[][] steps8 = {
			{-1, 0}, {1, 0}, {0, -1}, {0, 1},
			{-1, -1}, {1, 1}, {1, -1}, {-1, 1}
	};

	static final boolean check(int index, int lim){
		return (0 <= index && index < lim);
	}

	/////////////////////////////////////////////////////////////////////

	static final boolean checkBit(int mask, int bit){
		return (mask & (1 << bit)) != 0;
	}

	/////////////////////////////////////////////////////////////////////

	static final long getSum(int[] array) {
		long sum = 0;
		for (int value: array) {
			sum += value;
		}

		return sum;
	}

	static final Point getMinMax(int[] array) {
		int min = array[0];
		int max = array[0];

		for (int index = 0, size = array.length; index < size; ++index, ++index) {
			int value = array[index];

			if (index == size - 1) {
				min = min(min, value);
				max = max(max, value);
			} else {
				int otherValue = array[index + 1];

				if (value <= otherValue) {
					min = min(min, value);
					max = max(max, otherValue);
				} else {
					min = min(min, otherValue);
					max = max(max, value);
				}
			}
		}

		return new Point(min, max);
	}

	/////////////////////////////////////////////////////////////////////

	final static int INF = 1000 * 1000 * 1000;

	static class MinSegmentTree {
		int size;
		int[] tree;

		MinSegmentTree(int size) {
			this.size = size;
			this.tree = new int[size << 1];
		}

		void set(int index, int value) {
			set(1, 0, size - 1, index, value);
		}

		int set(int v, int l, int r, int index, int value) {
			if (l == r) {
				return tree[v] = value;
			} else {
				int vLeft = (v << 1);
				int vRight = (vLeft + 1);

				int m = ((l + r) >> 1);

				if (index <= m) {
					set(vLeft, l, m, index, value);
				} else {
					set(vRight, m + 1, r, index, value);
				}

				return tree[v] = min(tree[vLeft], tree[vRight]);
			}
		}

		int get(int left, int right) {
			return get(1, 0, size - 1, left, right);
		}

		int get(int v, int l, int r, int left, int right) {
			if (right < l || r < left) return INF;

			if (left == l && r == right) {
				return tree[v];
			} else {
				int vLeft = (v << 1);
				int vRight = (vLeft + 1);

				int m = ((l + r) >> 1);

				int leftRes = get(vLeft, l, m, left, min(m, right));
				int rightRes = get(vRight, m + 1, r, max(left, m + 1), right);

				return min(leftRes, rightRes);
			}
		}
	}

	class Area {
		Point min, max;
		int index;

		Area(Point min, Point max, int index) {
			this.min = min;
			this.max = max;
			this.index = index;
		}
	}

	void solve() throws IOException {
		int xSize = readInt() + 1;
		int ySize = readInt() + 1;

		int rocksCount = readInt();
		int queriesCount = readInt();

		Point[] rocks = readPointArray(rocksCount);

		Area[] areas = new Area[queriesCount];
		for (int i = 0; i < queriesCount; ++i) {
			areas[i] = new Area(readPoint(), readPoint(), i);
		}

		boolean[] answers = new boolean[queriesCount];
		Arrays.fill(answers, false);

		{
			// iterator -> x, tree -> y
			List<Area>[] xAreas = new List[xSize];
			for (int x = 0; x < xSize; ++x) {
				xAreas[x] = new ArrayList<E.Area>();
			}

			for (Area area : areas) {
				xAreas[area.max.x].add(area);
			}

			List<Point>[] xRocks = new List[xSize];
			for (int x = 0; x < xSize; ++x) {
				xRocks[x] = new ArrayList<Point>();
			}

			for (Point rock : rocks) {
				xRocks[rock.x].add(rock);
			}

			MinSegmentTree yTree = new MinSegmentTree(ySize);
			for (int x = 0; x < xSize; ++x) {
				for (Point rock : xRocks[x]) {
					yTree.set(rock.y, x);
				}

				for (Area area : xAreas[x]) {
					int minX = yTree.get(area.min.y, area.max.y);

					if (minX >= area.min.x) {
						answers[area.index] = true;
					}
				}
			}
		}
		{
			// iterator -> y, tree -> x
			List<Area>[] yAreas = new List[ySize];
			for (int y = 0; y < ySize; ++y) {
				yAreas[y] = new ArrayList<E.Area>();
			}

			for (Area area : areas) {
				yAreas[area.max.y].add(area);
			}

			List<Point>[] yRocks = new List[ySize];
			for (int y = 0; y < ySize; ++y) {
				yRocks[y] = new ArrayList<Point>();
			}

			for (Point rock : rocks) {
				yRocks[rock.y].add(rock);
			}

			MinSegmentTree xTree = new MinSegmentTree(xSize);
			for (int y = 0; y < ySize; ++y) {
				for (Point rock : yRocks[y]) {
					xTree.set(rock.x, y);
				}

				for (Area area : yAreas[y]) {
					int minY = xTree.get(area.min.x, area.max.x);

					if (minY >= area.min.y) {
						answers[area.index] = true;
					}
				}
			}
		}

		for (boolean answer : answers) {
			out.println(answer ? "YES" : "NO");
		}
	}
}


import java.util.*;
import java.io.*;
import java.awt.Point;
import java.math.BigDecimal;
import java.math.BigInteger;

import static java.lang.Math.*;

// Solution is at the bottom of code

public class E implements Runnable{

	final boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null;

	BufferedReader in;
	OutputWriter out;
	StringTokenizer tok = new StringTokenizer("");

	public static void main(String[] args){
		new Thread(null, new E(), "", 128 * (1L << 20)).start();
	}

	/////////////////////////////////////////////////////////////////////

	void init() throws FileNotFoundException{
		Locale.setDefault(Locale.US);

		if (ONLINE_JUDGE){
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new OutputWriter(System.out);
		}else{
			in = new BufferedReader(new FileReader("input.txt"));
			out = new OutputWriter("output.txt");
		}
	}

	////////////////////////////////////////////////////////////////

	long timeBegin, timeEnd;

	void time(){
		timeEnd = System.currentTimeMillis();
		System.err.println("Time = " + (timeEnd - timeBegin));
	}

	void debug(Object... objects){
		if (ONLINE_JUDGE){
			for (Object o: objects){
				System.err.println(o.toString());
			}
		}
	}

	/////////////////////////////////////////////////////////////////////

	public void run(){
		try{
			timeBegin = System.currentTimeMillis();
			Locale.setDefault(Locale.US);

			init();
			solve();

			out.close();
			time();
		}catch (Exception e){
			e.printStackTrace(System.err);
			System.exit(-1);
		}
	}

	/////////////////////////////////////////////////////////////////////

	String delim = " ";

	String readString() throws IOException{
		while(!tok.hasMoreTokens()){
			try{
				tok = new StringTokenizer(in.readLine());
			}catch (Exception e){
				return null;
			}
		}

		return tok.nextToken(delim);
	}

	String readLine() throws IOException{
		return in.readLine();
	}

	/////////////////////////////////////////////////////////////////

	final char NOT_A_SYMBOL = '\0';

	char readChar() throws IOException{
		int intValue = in.read();

		if (intValue == -1){
			return NOT_A_SYMBOL;
		}

		return (char) intValue;
	}

	char[] readCharArray() throws IOException{
		return readLine().toCharArray();
	}

	/////////////////////////////////////////////////////////////////

	int readInt() throws IOException {
		return Integer.parseInt(readString());
	}

	int[] readIntArray(int size) throws IOException {
		int[] array = new int[size];

		for (int index = 0; index < size; ++index){
			array[index] = readInt();
		}

		return array;
	}

	int[] readSortedIntArray(int size) throws IOException {
		Integer[] array = new Integer[size];

		for (int index = 0; index < size; ++index) {
			array[index] = readInt();
		}
		Arrays.sort(array);

		int[] sortedArray = new int[size];
		for (int index = 0; index < size; ++index) {
			sortedArray[index] = array[index];
		}

		return sortedArray;
	}

	int[] readIntArrayWithDecrease(int size) throws IOException {
		int[] array = readIntArray(size);

		for (int i = 0; i < size; ++i) {
			array[i]--;
		}

		return array;
	}

	///////////////////////////////////////////////////////////////////

	int[][] readIntMatrix(int rowsCount, int columnsCount) throws IOException {
		int[][] matrix = new int[rowsCount][];

		for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
			matrix[rowIndex] = readIntArray(columnsCount);
		}

		return matrix;
	}

	int[][] readIntMatrixWithDecrease(int rowsCount, int columnsCount) throws IOException {
		int[][] matrix = new int[rowsCount][];

		for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
			matrix[rowIndex] = readIntArrayWithDecrease(columnsCount);
		}

		return matrix;
	}

	///////////////////////////////////////////////////////////////////

	long readLong() throws IOException{
		return Long.parseLong(readString());
	}

	long[] readLongArray(int size) throws IOException{
		long[] array = new long[size];

		for (int index = 0; index < size; ++index){
			array[index] = readLong();
		}

		return array;
	}

	////////////////////////////////////////////////////////////////////

	double readDouble() throws IOException{
		return Double.parseDouble(readString());
	}

	double[] readDoubleArray(int size) throws IOException{
		double[] array = new double[size];

		for (int index = 0; index < size; ++index){
			array[index] = readDouble();
		}

		return array;
	}

	////////////////////////////////////////////////////////////////////

	BigInteger readBigInteger() throws IOException {
		return new BigInteger(readString());
	}

	BigDecimal readBigDecimal() throws IOException {
		return new BigDecimal(readString());
	}

	/////////////////////////////////////////////////////////////////////

	Point readPoint() throws IOException{
		int x = readInt();
		int y = readInt();
		return new Point(x, y);
	}

	Point[] readPointArray(int size) throws IOException{
		Point[] array = new Point[size];

		for (int index = 0; index < size; ++index){
			array[index] = readPoint();
		}

		return array;
	}

	/////////////////////////////////////////////////////////////////////

	List<Integer>[] readGraph(int vertexNumber, int edgeNumber)
	throws IOException{
		@SuppressWarnings("unchecked")
		List<Integer>[] graph = new List[vertexNumber];

		for (int index = 0; index < vertexNumber; ++index){
			graph[index] = new ArrayList<Integer>();
		}

		while (edgeNumber-- > 0){
			int from = readInt() - 1;
			int to = readInt() - 1;

			graph[from].add(to);
			graph[to].add(from);
		}

		return graph;
	}

	/////////////////////////////////////////////////////////////////////

	static class IntIndexPair {

		static Comparator<IntIndexPair> increaseComparator = new Comparator<E.IntIndexPair>() {

			@Override
			public int compare(IntIndexPair indexPair1, IntIndexPair indexPair2) {
				int value1 = indexPair1.value;
				int value2 = indexPair2.value;

				if (value1 != value2) return value1 - value2;

				int index1 = indexPair1.index;
				int index2 = indexPair2.index;

				return index1 - index2;
			}
		};

		static Comparator<IntIndexPair> decreaseComparator = new Comparator<E.IntIndexPair>() {

			@Override
			public int compare(IntIndexPair indexPair1, IntIndexPair indexPair2) {
				int value1 = indexPair1.value;
				int value2 = indexPair2.value;

				if (value1 != value2) return -(value1 - value2);

				int index1 = indexPair1.index;
				int index2 = indexPair2.index;

				return index1 - index2;
			}
		};

		int value, index;

		public IntIndexPair(int value, int index) {
			super();
			this.value = value;
			this.index = index;
		}

		public int getRealIndex() {
			return index + 1;
		}
	}

	IntIndexPair[] readIntIndexArray(int size) throws IOException {
		IntIndexPair[] array = new IntIndexPair[size];

		for (int index = 0; index < size; ++index) {
			array[index] = new IntIndexPair(readInt(), index);
		}

		return array;
	}

	/////////////////////////////////////////////////////////////////////

	static class OutputWriter extends PrintWriter {

		final int DEFAULT_PRECISION = 12;

		protected int precision;
		protected String format, formatWithSpace;

		{
			precision = DEFAULT_PRECISION;

			format = createFormat(precision);
			formatWithSpace = format + " ";
		}

		public OutputWriter(OutputStream out) {
			super(out);
		}

		public OutputWriter(String fileName) throws FileNotFoundException {
			super(fileName);
		}

		public int getPrecision() {
			return precision;
		}

		public void setPrecision(int precision) {
			precision = max(0, precision);
			this.precision = precision;

			format = createFormat(precision);
			formatWithSpace = format + " ";
		}

		private String createFormat(int precision){
			return "%." + precision + "f";
		}

		@Override
		public void print(double d){
			printf(format, d);
		}

		public void printWithSpace(double d){
			printf(formatWithSpace, d);
		}

		public void printAll(double...d){
			for (int i = 0; i < d.length - 1; ++i){
				printWithSpace(d[i]);
			}

			print(d[d.length - 1]);
		}

		@Override
		public void println(double d){
			printlnAll(d);
		}

		public void printlnAll(double... d){
			printAll(d);
			println();
		}
	}

	/////////////////////////////////////////////////////////////////////

	static final int[][] steps = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
	static final int[][] steps8 = {
			{-1, 0}, {1, 0}, {0, -1}, {0, 1},
			{-1, -1}, {1, 1}, {1, -1}, {-1, 1}
	};

	static final boolean check(int index, int lim){
		return (0 <= index && index < lim);
	}

	/////////////////////////////////////////////////////////////////////

	static final boolean checkBit(int mask, int bit){
		return (mask & (1 << bit)) != 0;
	}

	/////////////////////////////////////////////////////////////////////

	static final long getSum(int[] array) {
		long sum = 0;
		for (int value: array) {
			sum += value;
		}

		return sum;
	}

	static final Point getMinMax(int[] array) {
		int min = array[0];
		int max = array[0];

		for (int index = 0, size = array.length; index < size; ++index, ++index) {
			int value = array[index];

			if (index == size - 1) {
				min = min(min, value);
				max = max(max, value);
			} else {
				int otherValue = array[index + 1];

				if (value <= otherValue) {
					min = min(min, value);
					max = max(max, otherValue);
				} else {
					min = min(min, otherValue);
					max = max(max, value);
				}
			}
		}

		return new Point(min, max);
	}

	/////////////////////////////////////////////////////////////////////

	final static int INF = 1000 * 1000 * 1000;

	static class MinSegmentTree {
		int size;
		int[] tree;

		MinSegmentTree(int size) {
			this.size = size;
			this.tree = new int[size << 2];
		}

		void set(int index, int value) {
			set(1, 0, size - 1, index, value);
		}

		int set(int v, int l, int r, int index, int value) {
			if (l == r) {
				return tree[v] = value;
			} else {
				int vLeft = (v << 1);
				int vRight = (vLeft + 1);

				int m = ((l + r) >> 1);

				if (index <= m) {
					set(vLeft, l, m, index, value);
				} else {
					set(vRight, m + 1, r, index, value);
				}

				return tree[v] = min(tree[vLeft], tree[vRight]);
			}
		}

		int get(int left, int right) {
			return get(1, 0, size - 1, left, right);
		}

		int get(int v, int l, int r, int left, int right) {
			if (right < l || r < left) return INF;

			if (left == l && r == right) {
				return tree[v];
			} else {
				int vLeft = (v << 1);
				int vRight = (vLeft + 1);

				int m = ((l + r) >> 1);

				int leftRes = get(vLeft, l, m, left, min(m, right));
				int rightRes = get(vRight, m + 1, r, max(left, m + 1), right);

				return min(leftRes, rightRes);
			}
		}
	}

	class Area {
		Point min, max;
		int index;

		Area(Point min, Point max, int index) {
			this.min = min;
			this.max = max;
			this.index = index;
		}
	}

	void solve() throws IOException {
		int xSize = readInt() + 1;
		int ySize = readInt() + 1;

		int rocksCount = readInt();
		int queriesCount = readInt();

		Point[] rocks = readPointArray(rocksCount);

		Area[] areas = new Area[queriesCount];
		for (int i = 0; i < queriesCount; ++i) {
			areas[i] = new Area(readPoint(), readPoint(), i);
		}

		boolean[] answers = new boolean[queriesCount];
		Arrays.fill(answers, false);

		{
			// iterator -> x, tree -> y
			List<Area>[] xAreas = new List[xSize];
			for (int x = 0; x < xSize; ++x) {
				xAreas[x] = new ArrayList<E.Area>();
			}

			for (Area area : areas) {
				xAreas[area.max.x].add(area);
			}

			List<Point>[] xRocks = new List[xSize];
			for (int x = 0; x < xSize; ++x) {
				xRocks[x] = new ArrayList<Point>();
			}

			for (Point rock : rocks) {
				xRocks[rock.x].add(rock);
			}

			MinSegmentTree yTree = new MinSegmentTree(ySize);
			for (int x = 0; x < xSize; ++x) {
				for (Point rock : xRocks[x]) {
					yTree.set(rock.y, x);
				}

				for (Area area : xAreas[x]) {
					int minX = yTree.get(area.min.y, area.max.y);

					if (minX >= area.min.x) {
						answers[area.index] = true;
					}
				}
			}
		}
		{
			// iterator -> y, tree -> x
			List<Area>[] yAreas = new List[ySize];
			for (int y = 0; y < ySize; ++y) {
				yAreas[y] = new ArrayList<E.Area>();
			}

			for (Area area : areas) {
				yAreas[area.max.y].add(area);
			}

			List<Point>[] yRocks = new List[ySize];
			for (int y = 0; y < ySize; ++y) {
				yRocks[y] = new ArrayList<Point>();
			}

			for (Point rock : rocks) {
				yRocks[rock.y].add(rock);
			}

			MinSegmentTree xTree = new MinSegmentTree(xSize);
			for (int y = 0; y < ySize; ++y) {
				for (Point rock : yRocks[y]) {
					xTree.set(rock.x, y);
				}

				for (Area area : yAreas[y]) {
					int minY = xTree.get(area.min.x, area.max.x);

					if (minY >= area.min.y) {
						answers[area.index] = true;
					}
				}
			}
		}

		for (boolean answer : answers) {
			out.println(answer ? "YES" : "NO");
		}
	}
}


import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.File;
import java.io.Writer;
import java.util.List;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.FileReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author abra
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		OutputWriter out = new OutputWriter(outputStream);
		E solver = new E();
		solver.solve(1, in, out);
		out.close();
	}
}

class E extends SimpleSavingChelperSolution {

  class Node {

    Node left, right;
    int l, r, m, val;

    Node(int[] a, int l, int r) {
      this.l = l;
      this.r = r;
      m = (l + r) / 2;

      if (l + 1 == r) {
        val = a[l];
      } else {
        left = new Node(a, l, m);
        right = new Node(a, m, r);

        val = Math.min(left.val, right.val);
      }
    }

    void update(int i, int x) {
      if (l + 1 == r) {
        val = x;
      } else {
        if (i < m) {
          left.update(i, x);
        } else {
          right.update(i, x);
        }
        val = Math.min(left.val, right.val);
      }
    }

    int get(int ll, int rr) {
      if (ll == l && rr == r) {
        return val;
      }
      int res = Integer.MAX_VALUE;
      if (ll < m) {
        res = left.get(ll, Math.min(m, rr));
      }
      if (rr > m) {
        res = Math.min(res,
            right.get(Math.max(m, ll), rr)
        );
      }
      return res;
    }
  }

  public void solve(int testNumber) {
    int W = in.nextInt();
    int H = in.nextInt();

    int n = in.nextInt();
    int m = in.nextInt();

    int[][] lads = new int[n][2];
    int[][] rects = new int[m][4];

    for (int i = 0; i < n; i++) {
      lads[i][0] = in.nextInt() - 1;
      lads[i][1] = in.nextInt() - 1;
    }

    for (int i = 0; i < m; i++) {
      rects[i][0] = in.nextInt() - 1;
      rects[i][1] = in.nextInt() - 1;
      rects[i][2] = in.nextInt() - 1;
      rects[i][3] = in.nextInt() - 1;
    }

    List<Integer>[] ladsW = new List[W];
    List<Integer>[] rectEndsW = new List[W];

    List<Integer>[] ladsH = new List[H];
    List<Integer>[] rectEndsH = new List[H];

    for (int i = 0; i < W; i++) {
      ladsW[i] = new ArrayList<>();
      rectEndsW[i] = new ArrayList<>();
    }

    for (int i = 0; i < H; i++) {
      ladsH[i] = new ArrayList<>();
      rectEndsH[i] = new ArrayList<>();
    }

    for (int i = 0; i < n; i++) {
      ladsW[lads[i][0]].add(i);
      ladsH[lads[i][1]].add(i);
    }

    for (int i = 0; i < m; i++) {
      rectEndsW[rects[i][2]].add(i);
      rectEndsH[rects[i][3]].add(i);
    }

    boolean[] ans = new boolean[m];

    // DOWN -> TOP

    int[] a = new int[W];
    Arrays.fill(a, -1);
    Node node = new Node(a, 0, W);

    for (int i = 0; i < H; i++) {
      for (int j : ladsH[i]) {
        node.update(lads[j][0], i);
      }

      for (int j : rectEndsH[i]) {
        int t = node.get(rects[j][0], rects[j][2] + 1);

        if (t >= rects[j][1]) {
          ans[j] = true;
        }
      }
    }

    // LEFT -> RIGHT

    a = new int[H];
    Arrays.fill(a, -1);
    node = new Node(a, 0, H);

    for (int i = 0; i < W; i++) {
      for (int j : ladsW[i]) {
        node.update(lads[j][1], i);
      }

      for (int j : rectEndsW[i]) {
        int t = node.get(rects[j][1], rects[j][3] + 1);

        if (t >= rects[j][0]) {
          ans[j] = true;
        }
      }
    }

    for (int i = 0; i < m; i++) {
      out.println(ans[i] ? "YES" : "NO");
    }
  }
}

abstract class SimpleSavingChelperSolution extends SavingChelperSolution {

	public String processOutputPreCheck(int testNumber, String output) {
		return output;
	}

	public String processOutputPostCheck(int testNumber, String output) {
		return output;
	}
}

class InputReader {

	BufferedReader br;
	StringTokenizer in;

  public InputReader(InputStream inputStream) {
		br = new BufferedReader(new InputStreamReader(inputStream));
	}

	boolean hasMoreTokens() {
		while (in == null || !in.hasMoreTokens()) {
			String s = nextLine();
			if (s == null) {
				return false;
			}
			in = new StringTokenizer(s);
		}
		return true;
	}

	public String nextString() {
		return hasMoreTokens() ? in.nextToken() : null;
	}

	public String nextLine() {
		try {
			in = null; // riad legacy
			return br.readLine();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

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

}

abstract class SavingChelperSolution {

	protected int testNumber;

	public InputReader in;
	public OutputWriter out;

	private OutputWriter toFile;

	private boolean local = new File("chelper.properties").exists();

	public OutputWriter debug = local
			? new OutputWriter(System.out)
			: new OutputWriter(new OutputStream() {
				public void write(int b) {
				}
			});

	public SavingChelperSolution() {
		try {
			toFile = new OutputWriter("last_test_output.txt");
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	public abstract void solve(int testNumber);

	public abstract String processOutputPreCheck(int testNumber, String output);

	public abstract String processOutputPostCheck(int testNumber, String output);

	public void solve(int testNumber, InputReader in, OutputWriter out) {
		this.testNumber = testNumber;

		ByteArrayOutputStream substituteOutContents = new ByteArrayOutputStream();
		OutputWriter substituteOut = new OutputWriter(substituteOutContents);

		this.in = in;
		this.out = substituteOut;

		solve(testNumber);
		substituteOut.flush();

		String result = substituteOutContents.toString();

		result = processOutputPreCheck(testNumber, result);
		out.print(result);
		out.flush();

		if (local) {
			debug.flush();

			result = processOutputPostCheck(testNumber, result);
			toFile.print(result);
			toFile.flush();
		}
	}

}

class OutputWriter extends PrintWriter {

  public OutputWriter(String fileName) throws FileNotFoundException {
		super(fileName);
	}

	public OutputWriter(OutputStream outputStream) {
		super(outputStream);
	}

}


#include <bits/stdc++.h>

using namespace std;

#define MAX 100005
#define ff first
#define ss second
#define mp make_pair
#define pb push_back

struct Node{
    int x1, x2, y1, y2;
}qq[2 * MAX];

vector<int> vec[MAX];
vector<Node> arr[2 * MAX];
bool ans[2 * MAX];
int tree[4 * MAX];

void build(int node, int a, int b){
    if(a>b)
        return;
    if(a == b){
        tree[node] = 0;
        return;
    }

    int left, right;
    left = 2 * node, right = 2 * node + 1;

    build(left, a, (a+b)/2);
    build(right, (a+b)/2+1, b);

    tree[node] = 0;
}

void update(int node, int a, int b, int i, int j, int val){
    if(a>b || a>j || b<i)
        return;
    if(a == b){

        tree[node] = val;
        return;
    }

    int left, right;
    left = 2 * node, right = 2 * node + 1;

    update(left, a, (a+b)/2, i, j, val);
    update(right, (a+b)/2+1, b, i, j, val);

    tree[node] = min(tree[left], tree[right]);
}

int query(int node, int a, int b, int i, int j){
    if(a>b || a>j || b<i)
        return MAX;
    if(a>=i && b<=j)
        return tree[node];

    int left, right;
    left = 2 * node, right = 2 * node + 1;

    return min(query(left, a, (a+b)/2, i, j), query(right, (a+b)/2+1, b, i, j));
}

int main(){
    int n, m, k, q;
    scanf("%d %d %d %d", &n, &m, &k, &q);

    pair<int, int> rook[k];
    for(int i=0 ; i<k ; i++)
        scanf("%d %d", &rook[i].ff, &rook[i].ss);

    for(int i=0 ; i<q ; i++)
        scanf("%d %d %d %d", &qq[i].x1, &qq[i].y1, &qq[i].x2, &qq[i].y2);

    // inserting rooks row wise(y-coordinate)
    for(int i=0 ; i<k ; i++)
        vec[rook[i].ss].pb(rook[i].ff);

    for(int i=0 ; i<q ; i++)
        arr[qq[i].y2].pb((Node){qq[i].x1, qq[i].y1, qq[i].x2, i});

    for(int i=1 ; i<=m ; i++){
        for(int j=0 ; j<vec[i].size() ; j++)
            update(1, 1, n, vec[i][j], vec[i][j], i);

        for(int j=0 ; j<arr[i].size() ; j++){
            int temp = query(1, 1, n, arr[i][j].x1, arr[i][j].x2);
            ans[arr[i][j].y2] |= (temp<arr[i][j].y1 ? false : true);
            //cout<<arr[i][j].y2<<" "<<temp<<endl;
        }
    }

    for(int i=0 ; i<MAX ; i++)
        vec[i].clear();
    for(int i=0 ; i<2*MAX ; i++)
        arr[i].clear();

    build(1, 1, MAX-1);

    // inserting rooks column wise(x-coordinate)
    for(int i=0 ; i<k ; i++)
        vec[rook[i].ff].pb(rook[i].ss);

    for(int i=0 ; i<q ; i++)
        arr[qq[i].x2].pb((Node){qq[i].x1, qq[i].y1, i, qq[i].y2});

    for(int i=1 ; i<=n ; i++){
        for(int j=0 ; j<vec[i].size() ; j++)
            update(1, 1, m, vec[i][j], vec[i][j], i);

        for(int j=0 ; j<arr[i].size() ; j++){
            int temp = query(1, 1, m, arr[i][j].y1, arr[i][j].y2);
            ans[arr[i][j].x2] |= (temp<arr[i][j].x1 ? false : true);
        }
    }

    for(int i=0 ; i<q ; i++)
        printf("%s\n", ans[i] ? "YES" : "NO");

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define MAX 100005
#define ff first
#define ss second
#define mp make_pair
#define pb push_back

struct Node{
	int x1, y1, x2, y2;
}qq[2 * MAX];

vector<int> vec[MAX];
vector<Node> arr[2 * MAX];
bool ans[2 * MAX];
int tree[4 * MAX];

void build(int node, int a, int b){
	if(a>b)
		return;
	if(a == b){
		tree[node] = 0;
		return;
	}

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	build(left, a, (a+b)/2);
	build(right, (a+b)/2+1, b);

	tree[node] = 0;
}

void update(int node, int a, int b, int i, int j, int val){
	if(a>b || a>j || b<i)
		return;
	if(a == b){

		tree[node] = val;
		return;
	}

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	update(left, a, (a+b)/2, i, j, val);
	update(right, (a+b)/2+1, b, i, j, val);

	tree[node] = min(tree[left], tree[right]);
}

int query(int node, int a, int b, int i, int j){
	if(a>b || a>j || b<i)
		return MAX;
	if(a>=i && b<=j)
		return tree[node];

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	return min(query(left, a, (a+b)/2, i, j), query(right, (a+b)/2+1, b, i, j));
}

int main(){
	int n, m, k, q;
	scanf("%d %d %d %d", &n, &m, &k, &q);

	pair<int, int> rook[k];
	for(int i=0 ; i<k ; i++)
		scanf("%d %d", &rook[i].ff, &rook[i].ss);

	for(int i=0 ; i<q ; i++)
		scanf("%d %d %d %d", &qq[i].x1, &qq[i].y1, &qq[i].x2, &qq[i].y2);

	// inserting rooks row wise(y-coordinate)
	for(int i=0 ; i<k ; i++)
		vec[rook[i].ss].pb(rook[i].ff);

	for(int i=0 ; i<q ; i++)
		arr[qq[i].y2].pb((Node){qq[i].x1, qq[i].y1, qq[i].x2, i});

	for(int i=1 ; i<=m ; i++){
		for(int j=0 ; j<vec[i].size() ; j++)
			update(1, 1, n, vec[i][j], vec[i][j], i);

		for(int j=0 ; j<arr[i].size() ; j++){
			int temp = query(1, 1, n, arr[i][j].x1, arr[i][j].x2);
			ans[arr[i][j].y2] |= (temp<arr[i][j].y1 ? false : true);
		}
	}

	for(int i=0 ; i<MAX ; i++)
		vec[i].clear();
	for(int i=0 ; i<2*MAX ; i++)
		arr[i].clear();

	build(1, 1, MAX-1);

	// inserting rooks column wise(x-coordinate)
	for(int i=0 ; i<k ; i++)
		vec[rook[i].ff].pb(rook[i].ss);

	for(int i=0 ; i<q ; i++)
		arr[qq[i].x2].pb((Node){qq[i].x1, qq[i].y1, i, qq[i].y2});

	for(int i=1 ; i<=n ; i++){
		for(int j=0 ; j<vec[i].size() ; j++)
			update(1, 1, m, vec[i][j], vec[i][j], i);

		for(int j=0 ; j<arr[i].size() ; j++){
			int temp = query(1, 1, m, arr[i][j].y1, arr[i][j].y2);
			ans[arr[i][j].x2] |= (temp<arr[i][j].x1 ? false : true);
		}
	}

	for(int i=0 ; i<q ; i++)
		printf("%s\n", ans[i] ? "YES" : "NO");

	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define MAX 100005
#define ff first
#define ss second
#define mp make_pair
#define pb push_back

struct Node{
	int x1, y1, x2, y2;
}qq[2 * MAX];

vector<int> vec[MAX];
vector<Node> arr[MAX];
bool ans[2 * MAX];
int tree[4 * MAX];

void build(int node, int a, int b){
	if(a>b)
		return;
	if(a == b){
		tree[node] = 0;
		return;
	}

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	build(left, a, (a+b)/2);
	build(right, (a+b)/2+1, b);

	tree[node] = 0;
}

void update(int node, int a, int b, int i, int j, int val){
	if(a>b || a>j || b<i)
		return;
	if(a == b){

		tree[node] = val;
		return;
	}

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	update(left, a, (a+b)/2, i, j, val);
	update(right, (a+b)/2+1, b, i, j, val);

	tree[node] = min(tree[left], tree[right]);
}

int query(int node, int a, int b, int i, int j){
	if(a>b || a>j || b<i)
		return MAX;
	if(a>=i && b<=j)
		return tree[node];

	int left, right;
	left = 2 * node, right = 2 * node + 1;

	return min(query(left, a, (a+b)/2, i, j), query(right, (a+b)/2+1, b, i, j));
}

int main(){
	int n, m, k, q;
	scanf("%d %d %d %d", &n, &m, &k, &q);

	pair<int, int> rook[k];
	for(int i=0 ; i<k ; i++)
		scanf("%d %d", &rook[i].ff, &rook[i].ss);

	for(int i=0 ; i<q ; i++)
		scanf("%d %d %d %d", &qq[i].x1, &qq[i].y1, &qq[i].x2, &qq[i].y2);

	// inserting rooks row wise(y-coordinate)
	for(int i=0 ; i<k ; i++)
		vec[rook[i].ss].pb(rook[i].ff);

	for(int i=0 ; i<q ; i++)
		arr[qq[i].y2].pb((Node){qq[i].x1, qq[i].y1, qq[i].x2, i});

	for(int i=1 ; i<=m ; i++){
		for(int j=0 ; j<vec[i].size() ; j++)
			update(1, 1, n, vec[i][j], vec[i][j], i);

		for(int j=0 ; j<arr[i].size() ; j++){
			int temp = query(1, 1, n, arr[i][j].x1, arr[i][j].x2);
			ans[arr[i][j].y2] |= (temp<arr[i][j].y1 ? false : true);
		}
	}

	for(int i=0 ; i<MAX ; i++)
		vec[i].clear(), arr[i].clear();

	build(1, 1, MAX-1);

	// inserting rooks column wise(x-coordinate)
	for(int i=0 ; i<k ; i++)
		vec[rook[i].ff].pb(rook[i].ss);

	for(int i=0 ; i<q ; i++)
		arr[qq[i].x2].pb((Node){qq[i].x1, qq[i].y1, i, qq[i].y2});

	for(int i=1 ; i<=n ; i++){
		for(int j=0 ; j<vec[i].size() ; j++)
			update(1, 1, m, vec[i][j], vec[i][j], i);

		for(int j=0 ; j<arr[i].size() ; j++){
			int temp = query(1, 1, m, arr[i][j].y1, arr[i][j].y2);
			ans[arr[i][j].x2] |= (temp<arr[i][j].x1 ? false : true);
		}
	}

	for(int i=0 ; i<q ; i++)
		printf("%s\n", ans[i] ? "YES" : "NO");

	return 0;
}


#if 1
#include <functional>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <iomanip>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <list>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
typedef pair<int, int> pii;

const LD eps = 1e-9;
const LD pi = acos(-1.0);
const LL inf = 1e+9;

#define mp make_pair
#define pb push_back
#define X first
#define Y second

#define dbg(x) { cerr << #x << " = " << x << endl; }

// extended template
#pragma comment(linker, "/STACK:36777216")
typedef vector<int> vi;
typedef vector<vi> vvi;

#define forn(i, n) for (int i = 0; i < n; ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()

template<typename T> istream & operator >> (istream &, vector<T> &);
template<typename T> ostream & operator << (ostream &, const vector<T> &);

#define START clock_t _clock = clock();
#define END cerr << endl << "time: " << (clock() - _clock) / LD(CLOCKS_PER_SEC) << endl;

#define NAME "basket"

struct st
{
    static const int maxn = 100005;
    int t[4 * maxn];

    st()
    {
        memset(t, -1, sizeof(t));
    }

    void upd(int v, int tl, int tr, int pos, int val)
    {
        if (tl == tr && tl == pos)
            t[v] = val;
        else
        {
            int tm = (tl + tr) / 2;
            if (pos <= tm)
                upd(2 * v, tl, tm, pos, val);
            else
                upd(2 * v + 1, tm + 1, tr, pos, val);

            t[v] = min(t[2 * v], t[2 * v + 1]);
        }
    }

    int getMin(int v, int tl, int tr, int l, int r)
    {
        if (l > r)
            return inf;

        if (tl == l && tr == r)
            return t[v];
        else
        {
            int tm = (tl + tr) / 2;
            return min(getMin(2 * v, tl, tm, l, min(tm, r)),
                       getMin(2 * v + 1, tm + 1, tr, max(l, tm + 1), r));
        }
    }
};

struct sq
{
    int x1, y1, x2, y2, id;
    sq() {}
    sq(int x1, int y1, int x2, int y2) : x1(x1), y1(y1), x2(x2), y2(y2) {}

    friend bool operator< (const sq & a, const sq &b)
    {
        return a.x2 < b.x2;
    }
};

vector <int> get(vector <pii> pt, vector <sq> q, bool Ypos = 0)
{
    if (Ypos)
    {
        for (int i = 0; i < pt.size(); i++)
            swap(pt[i].X, pt[i].Y);

        for (int i = 0; i < q.size(); i++)
        {
            swap(q[i].x1, q[i].y1);
            swap(q[i].x2, q[i].y2);
        }
    }

    st _st;

    sort(pt.begin(), pt.end());
    sort(q.begin(), q.end());
    vector <int> res(q.size());

    int j = 0;
    const int maxn = 100000;
    for (int i = 0; i < q.size(); i++)
    {
        while (j < pt.size() && pt[j].X <= q[i].x2)
        {
            _st.upd(1, 0, maxn - 1, pt[j].Y, pt[j].X);
            j++;
        }

        int v = _st.getMin(1, 0, maxn - 1, q[i].y1, q[i].y2);
        if (v >= q[i].x1)
            res[q[i].id] = 1;
    }

    return res;
}

void solve()
{
    int n, m, k, q;
    scanf("%d %d %d %d", &n, &m, &k, &q);
    vector <pii> pt(k);
    vector <sq > Q(q);
    for (int i = 0; i < k; i++)
    {
        scanf("%d %d", &pt[i].X, &pt[i].Y);
        pt[i].X--;
        pt[i].Y--;
    }
    for (int i = 0; i < q; i++)
    {
        scanf("%d %d %d %d", &Q[i].x1, &Q[i].y1, &Q[i].x2, &Q[i].y2);
        Q[i].id = i;
        if (Q[i].x1 > Q[i].x2)
            swap(Q[i].x1, Q[i].x2);
        if (Q[i].y1 > Q[i].y2)
            swap(Q[i].y1, Q[i].y2);
        Q[i].x1--;
        Q[i].x2--;
        Q[i].y1--;
        Q[i].y2--;
    }

    vector <int> r1 = get(pt, Q),
                 r2 = get(pt, Q, 1);

    for (int i = 0; i < r1.size(); i++)
    {
        if (r1[i] || r2[i])
            printf("YES\n");
        else
            printf("NO\n");
    }
}

int main()
{
    START
    //freopen(NAME ".in", "r", stdin); freopen(NAME ".out", "w", stdout);
    //freopen("input.txt", "r", stdin); //freopen("output.txt", "w", stdout);
    //ios_base::sync_with_stdio(false);
    solve();
    END
    return 0;
}
/*******************************************
*******************************************/

template<typename T> istream & operator >> (istream &is, vector<T> &v)
{
    forn(i, v.size())
        is >> v[i];
    return is;
}
template<typename T> ostream & operator << (ostream &os, const vector<T> &v)
{
    forn(i, v.size())
        os << v[i] << " ";
    return os;
}
#endif


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

char mem[1 << 27], *memptr = mem;
void * operator new (size_t sz)
{
	memptr += sz;
	return memptr - sz;
}

class Treap
{
	struct Node
	{
		li pr, sz, v;
		Node *l, *r;

		Node (li v) : pr(rand() << 15 | rand()), sz(1), v(v), l(0), r(0) {}

		void Update ()
		{
			sz = 1 + SizeOf(l) + SizeOf(r);
		}

		static li SizeOf (Node *v)
		{
			return v ? v->sz : 0;
		}

		static void Update (Node *v)
		{
			if (v)
				v->Update();
		}
	};

	Node *root;

	void split (Node *v, li x, Node *&l, Node *&r)
	{
		if (!v)
			return void(r = l = 0);

		if (v->v <= x)
		{
			l = v;
			split(v->r, x, l->r, r);
			Node::Update(l);
		}
		else
		{
			r = v;
			split(v->l, x, l, r->l);
			Node::Update(r);
		}
	}

	void merge (Node *l, Node *r, Node *&v)
	{
		if (!l || !r)
			return void(v = l ? l : r);

		if (l->pr > r->pr)
		{
			v = l;
			merge(l->r, r, v->r);
		}
		else
		{
			v = r;
			merge(l, r->l, v->l);
		}
		Node::Update(v);
	}

	void erase (Node *&v, li key)
	{
		if (v->v == key)
			merge(v->l, v->r, v);
		else
			erase(key < v->v ? v->l : v->r, key);
		Node::Update(v);
	}

public:
	Treap () : root(0) {}

	void Insert (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		merge(l, new Node(v), l);
		merge(l, r, root);
	}

	li Greater (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		li res = Node::SizeOf(r);
		merge(l, r, root);
		return res;
	}

	void Erase (li v)
	{
		erase(root, v);
	}

	li GetRootValue ()
	{
		return root->v;
	}
};

class SegmentTree
{
	struct Node
	{
		li l, r;
		Treap *s;
		Node *left, *right;

		Node (li i) : l(i), r(i), s(new Treap()), left(0), right(0)
		{
			s->Insert(0);
		}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), s(new Treap()), left(left), right(right)
		{
			for (li i = r - l + 1; i; -- i)
				s->Insert(0);
		}

		bool IsLeaf ()
		{
			return l == r;
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	li set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
		{
			li val = v->s->GetRootValue();
			v->s->Erase(val);
			v->s->Insert(d);
			return val;
		}

		li res = set(i <= (v->l + v->r) / 2 ? v->left : v->right, i, d);
		v->s->Erase(res);
		v->s->Insert(d);
		return res;
	}

	li greater (Node *v, li l, li r, li d)
	{
		if (v->l > r || v->r < l)
			return 0;
		if (v->l >= l && v->r <= r)
			return v->s->Greater(d);
		return greater(v->left, l, r, d) + greater(v->right, l, r, d);
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Greater (li l, li r, li d)
	{
		return greater(root, l, r, d);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	srand(time(0));

	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Greater(r.y1, r.y2, r.x1 - 1) == r.y2 - r.y1 + 1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

class SegmentTree
{
	struct Node
	{
		li l, r, mn;
		Node *left, *right;

		Node (li i) : l(i), r(i), mn(0), left(0), right(0) {}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), left(left), right(right)
		{
			Update();
		}

		bool IsLeaf ()
		{
			return l == r;
		}

		void Update ()
		{
			mn = std::min(left->mn, right->mn);
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	void set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
			return void(v->mn = d);

		if (i <= (v->l + v->r) / 2)
			set(v->left, i, d);
		else
			set(v->right, i, d);
		v->Update();
	}

	li min (Node *v, li l, li r)
	{
		if (v->l > r || v->r < l)
			return INF;
		if (v->l >= l && v->r <= r)
			return v->mn;
		return std::min(min(v->left, l, r), min(v->right, l, r));
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Min (li l, li r)
	{
		return min(root, l, r);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Min(r.y1, r.y2) >= r.x1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

class SegmentTree
{
	struct Node
	{
		li l, r, mn;
		Node *left, *right;

		Node (li i) : l(i), r(i), mn(0), left(0), right(0) {}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), left(left), right(right)
		{
			Update();
		}

		bool IsLeaf ()
		{
			return l == r;
		}

		void Update ()
		{
			mn = std::min(left->mn, right->mn);
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	void set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
			return void(v->mn = d);

		if (i <= (v->l + v->r) / 2)
			set(v->left, i, d);
		else
			set(v->right, i, d);
		v->Update();
	}

	li min (Node *v, li l, li r)
	{
		if (v->l > r || v->r < l)
			return INF;
		if (v->l >= l && v->r <= r)
			return v->mn;
		return std::min(min(v->left, l, r), min(v->right, l, r));
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Min (li l, li r)
	{
		return min(root, l, r);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}
	sort(rs, rs + k);

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}
	sort(rects, rects + q);

	SegmentTree *t = new SegmentTree(1, h);
	for (li i = 0, j = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		for (; j < k && rs[j].x <= r.x2; ++ j)
		{
			t->Set(rs[j].y, rs[j].x);
		}

		ok[r.i] |= t->Min(r.y1, r.y2) >= r.x1;
	}

	t = new SegmentTree(1, w);
	for (li i = 0, j = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		for (; j < k && rs[j].y <= r.y2; ++ j)
		{
			t->Set(rs[j].x, rs[j].y);
		}

		ok[r.i] |= t->Min(r.x1, r.x2) >= r.y1;
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

class Treap
{
	struct Node
	{
		li pr, sz, v;
		Node *l, *r;

		Node (li v) : pr(rand() << 15 | rand()), sz(1), v(v), l(0), r(0) {}

		void Update ()
		{
			sz = 1 + SizeOf(l) + SizeOf(r);
		}

		static li SizeOf (Node *v)
		{
			return v ? v->sz : 0;
		}

		static void Update (Node *v)
		{
			if (v)
				v->Update();
		}
	};

	Node *root;

	void split (Node *v, li x, Node *&l, Node *&r)
	{
		if (!v)
			return void(r = l = 0);

		if (v->v <= x)
		{
			l = v;
			split(v->r, x, l->r, r);
			Node::Update(l);
		}
		else
		{
			r = v;
			split(v->l, x, l, r->l);
			Node::Update(r);
		}
	}

	void merge (Node *l, Node *r, Node *&v)
	{
		if (!l || !r)
			return void(v = l ? l : r);

		if (l->pr > r->pr)
		{
			v = l;
			merge(l->r, r, v->r);
		}
		else
		{
			v = r;
			merge(l, r->l, v->l);
		}
		Node::Update(v);
	}

	void erase (Node *&v, li key)
	{
		if (v->v == key)
			merge(v->l, v->r, v);
		else
			erase(key < v->v ? v->l : v->r, key);
		Node::Update(v);
	}

public:
	Treap () : root(0) {}

	void Insert (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		merge(l, new Node(v), l);
		merge(l, r, root);
	}

	li Greater (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		li res = Node::SizeOf(r);
		merge(l, r, root);
		return res;
	}

	void Erase (li v)
	{
		erase(root, v);
	}

	li GetRootValue ()
	{
		return root->v;
	}
};

class SegmentTree
{
	struct Node
	{
		li l, r;
		Treap *s;
		Node *left, *right;

		Node (li i) : l(i), r(i), s(new Treap()), left(0), right(0)
		{
			s->Insert(0);
		}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), s(new Treap()), left(left), right(right)
		{
			for (li i = r - l + 1; i; -- i)
				s->Insert(0);
		}

		bool IsLeaf ()
		{
			return l == r;
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	li set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
		{
			li val = v->s->GetRootValue();
			v->s->Erase(val);
			v->s->Insert(d);
			return val;
		}

		li res = set(i <= (v->l + v->r) / 2 ? v->left : v->right, i, d);
		v->s->Erase(res);
		v->s->Insert(d);
		return res;
	}

	li greater (Node *v, li l, li r, li d)
	{
		if (v->l > r || v->r < l)
			return 0;
		if (v->l >= l && v->r <= r)
			return v->s->Greater(d);
		return greater(v->left, l, r, d) + greater(v->right, l, r, d);
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Greater (li l, li r, li d)
	{
		return greater(root, l, r, d);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	srand(time(0));

	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Greater(r.y1, r.y2, r.x1 - 1) == r.y2 - r.y1 + 1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

li nextInt ()
{
	li c;
	while (!isdigit(c = getchar()));
	li x = c - '0';
	while (isdigit(c = getchar()))
		x = 10 * x + c - '0';
	return x;
}

char mem[1 << 27], *memptr = mem;
void * operator new (size_t sz)
{
	memptr += sz;
	return memptr - sz;
}

class Treap
{
	struct Node
	{
		li pr, sz, v;
		Node *l, *r;

		Node (li v) : pr(rand() << 15 | rand()), sz(1), v(v), l(0), r(0) {}

		void Update ()
		{
			sz = 1 + SizeOf(l) + SizeOf(r);
		}

		static li SizeOf (Node *v)
		{
			return v ? v->sz : 0;
		}

		static void Update (Node *v)
		{
			if (v)
				v->Update();
		}
	};

	Node *root;

	void split (Node *v, li x, Node *&l, Node *&r)
	{
		if (!v)
			return void(r = l = 0);

		if (v->v <= x)
		{
			l = v;
			split(v->r, x, l->r, r);
			Node::Update(l);
		}
		else
		{
			r = v;
			split(v->l, x, l, r->l);
			Node::Update(r);
		}
	}

	void merge (Node *l, Node *r, Node *&v)
	{
		if (!l || !r)
			return void(v = l ? l : r);

		if (l->pr > r->pr)
		{
			v = l;
			merge(l->r, r, v->r);
		}
		else
		{
			v = r;
			merge(l, r->l, v->l);
		}
		Node::Update(v);
	}

	void erase (Node *&v, li key)
	{
		if (v->v == key)
			merge(v->l, v->r, v);
		else
			erase(key < v->v ? v->l : v->r, key);
		Node::Update(v);
	}

public:
	Treap () : root(0) {}

	void Insert (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		merge(l, new Node(v), l);
		merge(l, r, root);
	}

	li Greater (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		li res = Node::SizeOf(r);
		merge(l, r, root);
		return res;
	}

	void Erase (li v)
	{
		erase(root, v);
	}

	li GetRootValue ()
	{
		return root->v;
	}
};

class SegmentTree
{
	struct Node
	{
		li l, r;
		Treap *s;
		Node *left, *right;

		Node (li i) : l(i), r(i), s(new Treap()), left(0), right(0)
		{
			s->Insert(0);
		}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), s(new Treap()), left(left), right(right)
		{
			for (li i = r - l + 1; i; -- i)
				s->Insert(0);
		}

		bool IsLeaf ()
		{
			return l == r;
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	li set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
		{
			li val = v->s->GetRootValue();
			v->s->Erase(val);
			v->s->Insert(d);
			return val;
		}

		li res = set(i <= (v->l + v->r) / 2 ? v->left : v->right, i, d);
		v->s->Erase(res);
		v->s->Insert(d);
		return res;
	}

	li greater (Node *v, li l, li r, li d)
	{
		if (v->l > r || v->r < l)
			return 0;
		if (v->l >= l && v->r <= r)
			return v->s->Greater(d);
		return greater(v->left, l, r, d) + greater(v->right, l, r, d);
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Greater (li l, li r, li d)
	{
		return greater(root, l, r, d);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	srand(time(0));

	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Greater(r.y1, r.y2, r.x1 - 1) == r.y2 - r.y1 + 1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		puts(ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

class Treap
{
	struct Node
	{
		li pr, sz, v;
		Node *l, *r;

		Node (li v) : pr(rand() << 15 | rand()), sz(1), v(v), l(0), r(0) {}

		void Update ()
		{
			sz = 1 + SizeOf(l) + SizeOf(r);
		}

		static li SizeOf (Node *v)
		{
			return v ? v->sz : 0;
		}

		static void Update (Node *v)
		{
			if (v)
				v->Update();
		}
	};

	Node *root;

	void split (Node *v, li x, Node *&l, Node *&r)
	{
		if (!v)
			return void(r = l = 0);

		if (v->v <= x)
		{
			l = v;
			split(v->r, x, l->r, r);
			Node::Update(l);
		}
		else
		{
			r = v;
			split(v->l, x, l, r->l);
			Node::Update(r);
		}
	}

	void merge (Node *l, Node *r, Node *&v)
	{
		if (!l || !r)
			return void(v = l ? l : r);

		if (l->pr > r->pr)
		{
			v = l;
			merge(l->r, r, v->r);
		}
		else
		{
			v = r;
			merge(l, r->l, v->l);
		}
		Node::Update(v);
	}

	void erase (Node *&v, li key)
	{
		if (v->v == key)
			merge(v->l, v->r, v);
		else
			erase(key < v->v ? v->l : v->r, key);
	}

public:
	Treap () : root(0) {}

	void PushBack (li v)
	{
		merge(root, new Node(v), root);
	}

	void Insert (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		merge(l, new Node(v), l);
		merge(l, r, root);
	}

	li Greater (li v)
	{
		Node *l, *r;
		split(root, v - 1, l, r);
		li res = Node::SizeOf(r);
		merge(l, r, root);
		return res;
	}

	void Erase (li v)
	{
		erase(root, v);
	}

	li GetRootValue ()
	{
		return root->v;
	}
};

class SegmentTree
{
	struct Node
	{
		li l, r;
		Treap *s;
		Node *left, *right;

		Node (li i) : l(i), r(i), s(new Treap()), left(0), right(0)
		{
			s->PushBack(0);
		}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), s(new Treap()), left(left), right(right)
		{
			for (li i = r - l + 1; i; -- i)
				s->PushBack(0);
		}

		bool IsLeaf ()
		{
			return l == r;
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	li set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
		{
			li val = v->s->GetRootValue();
			v->s->Erase(val);
			v->s->PushBack(d);
			return val;
		}

		if (i <= (v->l + v->r) / 2)
		{
			li res = set(v->left, i, d);
			v->s->Erase(res);
			v->s->Insert(d);
			return res;
		}
		else
		{
			li res = set(v->right, i, d);
			v->s->Erase(res);
			v->s->Insert(d);
			return res;
		}
	}

	li greater (Node *v, li l, li r, li d)
	{
		if (v->l > r || v->r < l)
			return 0;
		if (v->l >= l && v->r <= r)
			return v->s->Greater(d);
		return greater(v->left, l, r, d) + greater(v->right, l, r, d);
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Greater (li l, li r, li d)
	{
		return greater(root, l, r, d);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Greater(r.y1, r.y2, r.x1) == r.y2 - r.y1 + 1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}


#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <iterator>
#include <list>
#include <set>
#include <queue>
#include <numeric>
#include <cstdlib>
#include <ctime>
#include <limits>
#include <valarray>
#include <cassert>

#define all(c) (c).begin(), (c).end()

using namespace std;

typedef long long lli;
typedef int li;

template <class T>
bool Maximize (T &v, T nv) { if (nv > v) return v = nv, 1; return 0; }

template <class T>
bool Minimize (T &v, T nv) { if (nv < v) return v = nv, 1; return 0; }

template <class T>
T Mod (T &v, T mod) { return v = (v % mod + mod) % mod; }

const lli INFLL = numeric_limits<lli>::max();
const li INF = numeric_limits<li>::max(), K = 2e5 + 1, Q = 2e5 + 1;
const li di[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

class Treap
{
	struct Node
	{
		li pr, sz, v;
		Node *l, *r;

		Node (li v) : pr(rand() << 15 | rand()), sz(1), v(v), l(0), r(0) {}

		void Update ()
		{
			sz = 1 + SizeOf(l) + SizeOf(r);
		}

		static li SizeOf (Node *v)
		{
			return v ? v->sz : 0;
		}

		static void Update (Node *v)
		{
			if (v)
				v->Update();
		}
	};

	Node *root;

	void split (Node *v, li x, Node *&l, Node *&r)
	{
		if (!v)
			return void(r = l = 0);

		if (v->v <= x)
		{
			l = v;
			split(v->r, x, l->r, r);
			Node::Update(l);
		}
		else
		{
			r = v;
			split(v->l, x, l, r->l);
			Node::Update(r);
		}
	}

	void merge (Node *l, Node *r, Node *&v)
	{
		if (!l || !r)
			return void(v = l ? l : r);

		if (l->pr > r->pr)
		{
			v = l;
			merge(l->r, r, v->r);
		}
		else
		{
			v = r;
			merge(l, r->l, v->l);
		}
		Node::Update(v);
	}

	void erase (Node *&v, li key)
	{
		if (v->v == key)
			merge(v->l, v->r, v);
		else
			erase(key < v->v ? v->l : v->r, key);
	}

public:
	Treap () : root(0) {}

	void PushBack (li v)
	{
		merge(root, new Node(v), root);
	}

	void Insert (li v)
	{
		Node *l, *r;
		split(root, v, l, r);
		merge(l, new Node(v), l);
		merge(l, r, root);
	}

	li Greater (li v)
	{
		Node *l, *r;
		split(root, v - 1, l, r);
		li res = Node::SizeOf(r);
		merge(l, r, root);
		return res;
	}

	void Erase (li v)
	{
		erase(root, v);
	}

	li GetRootValue ()
	{
		return root->v;
	}
};

class SegmentTree
{
	struct Node
	{
		li l, r;
		Treap *s;
		Node *left, *right;

		Node (li i) : l(i), r(i), s(new Treap()), left(0), right(0)
		{
			s->PushBack(0);
		}

		Node (li l, li r, Node *left, Node *right) : l(l), r(r), s(new Treap()), left(left), right(right)
		{
			for (li i = r - l + 1; i; -- i)
				s->PushBack(0);
		}

		bool IsLeaf ()
		{
			return l == r;
		}
	};

	Node *root;

	Node* build (li l, li r)
	{
		return l == r ? new Node(l) : new Node(l, r, build(l, (l + r) / 2), build((l + r) / 2 + 1, r));
	}

	li set (Node *v, li i, li d)
	{
		if (v->IsLeaf())
		{
			li val = v->s->GetRootValue();
			v->s->Erase(val);
			v->s->PushBack(d);
			return val;
		}

		if (i <= (v->l + v->r) / 2)
		{
			li res = set(v->left, i, d);
			v->s->Erase(res);
			v->s->Insert(d);
			return res;
		}
		else
		{
			li res = set(v->right, i, d);
			v->s->Erase(res);
			v->s->Insert(d);
			return res;
		}
	}

	li greater (Node *v, li l, li r, li d)
	{
		if (v->l > r || v->r < l)
			return 0;
		if (v->l >= l && v->r <= r)
			return v->s->Greater(d);
		return greater(v->left, l, r, d) + greater(v->right, l, r, d);
	}

public:
	SegmentTree (li l, li r)
	{
		root = build(l, r);
	}

	void Set (li i, li d)
	{
		set(root, i, d);
	}

	li Greater (li l, li r, li d)
	{
		return greater(root, l, r, d);
	}
};

struct Rook
{
	li x, y;

	bool operator < (const Rook &r) const
	{
		return x < r.x;
	}
};

struct Rect
{
	li x1, x2, y1, y2, i;

	bool operator < (const Rect &r) const
	{
		return x2 < r.x2;
	}
};

Rook rs[K];
Rect rects[Q];
bool ok[Q];

void solve ()
{
	li w, h, k, q;
	scanf("%d %d %d %d", &w, &h, &k, &q);

	for (li i = 0; i < k; ++ i)
	{
		Rook &r = rs[i];
		scanf("%d %d", &r.x, &r.y);
	}

	for (li i = 0; i < q; ++ i)
	{
		Rect &r = rects[i];
		r.i = i;
		scanf("%d %d %d %d", &r.x1, &r.y1, &r.x2, &r.y2);
	}

	for (li jesuisstdpide = 0; jesuisstdpide < 2; ++ jesuisstdpide)
	{
		sort(rs, rs + k);
		sort(rects, rects + q);
		SegmentTree *t = new SegmentTree(1, h);
		for (li i = 0, j = 0; i < q; ++ i)
		{
			Rect &r = rects[i];
			for (; j < k && rs[j].x <= r.x2; ++ j)
			{
				t->Set(rs[j].y, rs[j].x);
				swap(rs[j].x, rs[j].y);
			}

			ok[r.i] |= t->Greater(r.y1, r.y2, r.x1) == r.y2 - r.y1 + 1;
			swap(r.x1, r.y1);
			swap(r.x2, r.y2);
		}
		swap(h, w);
	}

	for (li i = 0; i < q; ++ i)
	{
		printf("%s\n", ok[i] ? "YES" : "NO");
	}
}

void init ()
{
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
}

int main()
{
	init();
	solve();
	return 0;
}