#include <iostream>
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <cmath>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <bitset>
#include <numeric>
#include <climits>
#include <cfloat>
using namespace std;

class Point
{
public:
    int y, x;
    Point(){
        y = x = 0;
    }
    Point(int y0, int x0){
        y = y0;
        x = x0;
    }
    Point operator+(const Point& p) const{
        return Point(y + p.y, x + p.x);
    }
    Point operator-(const Point& p) const{
        return Point(y - p.y, x - p.x);
    }
    Point operator*(int a) const{
        return Point(y * a, x * a);
    }
    double length2() const{
        return y * y + x * x;
    }
    double dist2(const Point& p) const{
        return (y - p.y) * (y - p.y) + (x - p.x) * (x - p.x);
    }
    int dot(const Point& p) const{
        return y * p.y + x * p.x; // |a|*|b|*cosÆ
    }
    int cross(const Point& p) const{
        return x * p.y - y * p.x; // |a|*|b|*sinÆ
    }
    bool operator<(const Point& p) const{
        return x < p.x || (x == p.x && y < p.y);
    }
};

void convexHull(const vector<Point>& p0, vector<Point>& cv)
{
    if(p0.size() < 3){
        cv = p0;
        return;
    }

    vector<Point> p = p0;
    sort(p.begin(), p.end());
    int n = p.size();

    int j = 0;
    cv.clear();
    for(int i=0; i<2*n-1; ++i){
        Point tmp = (i<n? p[i]:p[2*(n-1)-i]);
        while(j >= 2 && (tmp-cv[j-2]).cross(cv[j-1]-cv[j-2]) < 0){
            cv.pop_back();
            -- j;
        }
        cv.push_back(tmp);
        ++ j;
    }
    cv.pop_back();
}

bool segmentsCollide(const Point& a1, const Point& a2, const Point& b1, const Point& b2)
{
    if(min(a1.x, a2.x) > max(b1.x, b2.x) || min(b1.x, b2.x) > max(a1.x, a2.x) || min(a1.y, a2.y) > max(b1.y, b2.y) || min(b1.y, b2.y) > max(a1.y, a2.y))
        return false;

    return ((long long)((a2-a1).cross(b1-a1)) * (a2-a1).cross(b2-a1) <= 0) && ((long long)((b2-b1).cross(a1-b1)) * (b2-b1).cross(a2-b1) <= 0);
}

bool convexContain(const vector<Point>& cp, const Point& p)
{
    int n = cp.size();
    bool ret1 = true;
    bool ret2 = true;
    for(int i=0; i<n; ++i){
        int a = (cp[(i+1)%n] - cp[i]).cross(p - cp[i]);
        if(a < 0)
            ret1 = false;
        if(a > 0)
            ret2 = false;
    }
    return ret1 || ret2;
}

bool polygonsCollide(const vector<Point>& cp1, const vector<Point>& cp2)
{
    int n = cp1.size();
    int m = cp2.size();
    for(int i=0; i<n; ++i){
        for(int j=0; j<m; ++j){
            if(segmentsCollide(cp1[i], cp1[(i+1)%n], cp2[j], cp2[(j+1)%m]))
                return true;
        }
    }

    if(cp1.size() >= 3 && convexContain(cp1, cp2[0]))
        return true;
    if(cp2.size() >= 3 && convexContain(cp2, cp1[0]))
        return true;
    return false;
}

int main()
{
    for(;;){
        int n, m;
        cin >> n >> m;
        if(n == 0)
            return 0;

        vector<Point> p1(n), p2(m);
        for(int i=0; i<n; ++i)
            cin >> p1[i].x >> p1[i].y;
        for(int i=0; i<m; ++i)
            cin >> p2[i].x >> p2[i].y;

        vector<Point> cv1, cv2;
        convexHull(p1, cv1);
        convexHull(p2, cv2);

        if(polygonsCollide(cv1, cv2))
            cout << "NO" << endl;
        else
            cout << "YES" << endl;
    }
}

Measured memory_bytes: 900