import std.stdio;
import std.ascii;
import std.c.stdio;
import std.range;
import std.array;
import std.functional;
import std.algorithm;
import std.conv;
import std.container;
import std.math;
import std.numeric;
import std.string;
import std.c.string;
import std.regex;
import std.typecons;

const EPS = 1e-9;

struct Point {
    double x, y;
    double norm() const { return sqrt(x * x + y * y); }
    Point unit() const {
        double l = norm();
        return Point(x / l, y / l);
    }
    Point opBinary(alias op)(in Point p) const {
        return Point(mixin("x" ~ op ~ "p.x"), mixin("y" ~ op ~ "p.y"));
    }
    Point opBinary(alias op)(double a) const {
        return Point(mixin("x" ~ op ~ "a"), mixin("y" ~ op ~ "a"));
    }
    static double Distance(in Point a, in Point b) {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    static double Dot(in Point a, in Point b) { return a.x * b.x + a.y * b.y; }
    static double Cross(in Point a, in Point b) { return a.x * b.y - a.y * b.x; }
    static int CCW(Point a, Point b, Point c){
        b = b - a; c = c - a;
        if (Cross(b, c) > EPS) return +1; // テ・ツ渉催ヲツ卍づィツィツ暗・ツ堕ィテ」ツつ?
        if (Cross(b, c) < -EPS) return -1; // テヲツ卍づィツィツ暗・ツ堕ィテ」ツつ?
        if (Dot(b, c) < 0) return +2; // c--a--b テァツ崢エテァツキツ?
        if (b.norm() < c.norm()) return -2; // a--b--c テァツ崢エテァツキツ?
        return 0; // a--c--b テァツ崢エテァツキツ?
    }
};

struct Segment {
    Point a, b;
    bool contains(in Point p) const {
        return Point.CCW(a, b, p) == 0;
    }
    bool intersect(in Segment s) const {
        return Point.CCW(a, b, s.a) * Point.CCW(a, b, s.b) <= 0 &&
            Point.CCW(s.a, s.b, a) * Point.CCW(s.a, s.b, b) <= 0;
    }
}

struct Polygon {
    Point[] vs;
    bool edgesContain(in Point p) const {
        foreach (i; 0 .. vs.length) {
            auto s = Segment(vs[i], vs[next(i)]);
            if (s.contains(p)) return true;
        }
        return false;
    }
    bool contains(in Point p) const {
        if (edgesContain(p)) return false;
        int Count = 0;
        foreach (i; 0 .. vs.length) {
            Point p1 = vs[i],
                  p2 = vs[next(i)];
            if (p1.y > p2.y) swap(p1, p2);
            if ( (p1.y - p.y) <= 0 && 0 < (p2.y - p.y) && Point.CCW(p1, p2, p) == 1)
                Count++;
        }
        return Count % 2 == 1;
    }
    bool isConvex() {
        foreach (i; 0 .. vs.length) {
            Point a = vs[prev(i)], b = vs[i], c = vs[next(i)];
            if (Point.CCW(a, b, c) != 1) return false;
        }
        return true;
    }
    size_t next(size_t i) const {
        return (i + 1) % vs.length;
    }
    size_t prev(size_t i) const {
        return (i + vs.length - 1) % vs.length;
    }
    /* テ、ツクツ偲」ツ?暗」ツつ嘉」ツつ古」ツ?淌ァツつケテゥツ崢?・ツ青暗」ツ?ョテ・ツ?クテ・ツ個?」ツつ津」ツ?凝」ツ?暗」ツ??
     * psテ」ツ?ッ3テ」ツ?、テ、ツサツ・テ、ツクツ甘」ツ?ョティツヲツ?ァツエツ?」ツつ津ヲツ個?」ツ?淌」ツ?ュテ」ツ?ーテ」ツ?ェテ」ツつ嘉」ツ?ェテ」ツ??
     *
     * テ」ツ?禿」ツ?ョテ・ツョツ淌ィツ」ツ?」ツ?ッテ・ツ?クテ・ツ、ツ堙ィツァツ津・ツスツ「テ」ツ?ョティツソツ氾、ツクツ甘」ツ?ォテ・ツュツ佚・ツ慊ィテ」ツ?凖」ツつ凝ァツつケテ」ツつづ・ツ青ォテ」ツつ?」ツつ?
     * テ・ツ?クテ・ツ、ツ堙ィツァツ津・ツスツ「テ」ツ?ョテゥツ?づァツつケテ」ツ?ョテ」ツ?ソテ」ツ?古・ツソツ?ィツヲツ?」ツ?ェテ・ツ?エテ・ツ青暗」ツ?ッ 144, 148ティツ。ツ古ァツ崢ョテ」ツ?ョ2テ」ツ?、テァツ崢ョテ」ツ?ョテヲツ敖。テ、ツサツカテ」ツつ?
     * Point::CCW(Ret[k - 2], Ret[k - 1], ps[i] <= 0)テ」ツ?ォテ・ツ、ツ嘉ヲツ崢エテ」ツ?凖」ツつ?*/
    static Polygon convexHull(Point[] ps) {
        ps.sort!"a.x < b.x";
        auto N = ps.length;
        int k = 0;
        auto Ret = new Point[N * 2];
        for (int i = 0; i < N; Ret[k++] = ps[i++]) {
            while (k >= 2 && Point.CCW(Ret[k - 2], Ret[k - 1], ps[i]) == -1)
                k--;
        }
        for (int i = cast(int)N - 2, t = k + 1; i >= 0; Ret[k++] = ps[i--]) {
            while (k >= t && Point.CCW(Ret[k - 2], Ret[k - 1], ps[i]) == -1)
                k--;
        }
        Ret = Ret[0 .. k - 1];
        return Polygon(Ret);
    }
};

void main() {
    int N, M;
    Point[] B, W;
    bool input() {
        scanf("%d %d\n", &N, &M);
        if (N == 0 && M == 0) return false;
        B.clear; W.clear;
        foreach (i; 0 .. N) {
            int x, y;
            scanf("%d %d\n", &x, &y);
            B ~= Point(x, y);
        }
        foreach (i; 0 .. M) {
            int x, y;
            scanf("%d %d\n", &x, &y);
            W ~= Point(x, y);
        }
        return true;
    }
    bool check(in Polygon a, in Polygon b) {
        foreach (i; 0 .. a.vs.length) {
            foreach (j; 0 .. b.vs.length) {
                if (a.contains(b.vs[j])) return false;
                if (b.contains(a.vs[i])) return false;
                auto s = Segment(a.vs[i], a.vs[(i + 1) % a.vs.length]);
                auto t = Segment(b.vs[j], b.vs[(j + 1) % b.vs.length]);
                if (s.intersect(t)) return false;
            }
        }
        return true;
    }
    void solve() {
        static if (false) {
            writeln([N, M]);
            writeln(B);
            writeln(W);
        }
        if (N < M) {
            swap(N, M);
            swap(B, W);
        }
        if (N == 1) {
            writeln("YES");
        } else if (N == 2) {
            if (M == 1) {
                writeln(Segment(B[0], B[1]).contains(W[0]) ? "NO" : "YES");
            } else {
                writeln(Segment(B[0], B[1]).intersect(Segment(W[0], W[1])) ? "NO" : "YES");
            }
        } else {
            Polygon a = Polygon.convexHull(B);
            Polygon b = Polygon.convexHull(W);
            writeln(check(a, b) ? "YES" : "NO");
        }
    }
    while (input) solve;
}