#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 100

class Point{
public:
	double x,y;

	Point(double x = 0,double y = 0):x(x),y(y){}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &arg) const{ //sortする際にはこのメソッドが必要
		if(y != arg.y)return y < arg.y;
		return x < arg.x;
	};

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}
};

struct Line{
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	Point p[2];
};

typedef Point Vector;
typedef vector<Point> Polygon;

int num_point,Q;
int num_black,num_white;
Point black[NUM],white[NUM];
vector<Point> UP_BLACK,DOWN_BLACK,UP_WHITE,DOWN_WHITE;


double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

//ベクトルaとbの外積を求める関数
double cross(Vector a,Vector b){
	return a.x*b.y-a.y*b.x;
}

//ベクトルaとbの内積を求める関数
double dot(Vector a,Vector b){
	return a.x*b.x + a.y*b.y;
}

Point calc_minus(Point a,Point b){
	Point ret;

	ret.x = a.x-b.x;
	ret.y = a.y-b.y;

	return ret;
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

//trueなら凸
bool calcGaiseki(Point left,Point base, Point right){
	double gaiseki = (left.x-base.x)*(right.y - base.y)-(left.y-base.y)*(right.x-base.x);
	if(gaiseki < -0.00000001)return false;
	else{
		return true;
	}
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}

bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

//他角形g1とg2が交差するかどうか調べる関数
bool intersect(const Polygon g1,const Polygon g2){

	int size_1 = g1.size(),size_2 = g2.size();

	for(int i = 0; i < size_1; i++){
		for(int k = 0; k < size_2; k++){
			if(is_Cross(Line(g1[i],g1[(i+1)%size_1]),Line(g2[k],g2[(k+1)%size_2]))){
				return true;
			}
		}
	}

	for(int i = 0; i < size_1; i++){
		if(contains(g2,g1[i]))return true;
	}

	for(int i = 0; i < size_2; i++){
		if(contains(g1,g2[i]))return true;
	}

	return false;
}


void func(){

	UP_BLACK.clear();
	UP_WHITE.clear();
	DOWN_BLACK.clear();
	DOWN_WHITE.clear();

	//黒を線分で囲む
	for(int i = 0; i < num_black; i++){
		scanf("%lf %lf",&black[i].x,&black[i].y);
	}

	if(num_black > 1){

		sort(black,black+num_black);

		UP_BLACK.push_back(black[0]);
		UP_BLACK.push_back(black[1]);

		DOWN_BLACK.push_back(black[num_black-1]);
		DOWN_BLACK.push_back(black[num_black-2]);

		for(int i = 2; i < num_black; i++){
			while(UP_BLACK.size() > 1 && calcGaiseki(UP_BLACK[UP_BLACK.size()-2],UP_BLACK[UP_BLACK.size()-1],black[i]) == false)UP_BLACK.pop_back();
			UP_BLACK.push_back(black[i]);
		}

		for(int i = num_black-3; i >= 0; i--){
			while(DOWN_BLACK.size() > 1 && calcGaiseki(DOWN_BLACK[DOWN_BLACK.size()-2],DOWN_BLACK[DOWN_BLACK.size()-1],black[i]) == false){
				DOWN_BLACK.pop_back();
			}
			DOWN_BLACK.push_back(black[i]);
		}
	}

	Polygon g_black;

	for(int i = DOWN_BLACK.size()-1; i >= 1;i--)g_black.push_back(DOWN_BLACK[i]);
	for(int i = UP_BLACK.size()-1; i >= 1 ;i--)g_black.push_back(UP_BLACK[i]);

	//白を線分で囲む
	for(int i = 0; i < num_white; i++){
		scanf("%lf %lf",&white[i].x,&white[i].y);
	}

	if(num_white > 1){
		sort(white,white+num_white);

		UP_WHITE.push_back(white[0]);
		UP_WHITE.push_back(white[1]);

		DOWN_WHITE.push_back(white[num_white-1]);
		DOWN_WHITE.push_back(white[num_white-2]);

		for(int i = 2; i < num_white; i++){
			while(UP_WHITE.size() > 1 && calcGaiseki(UP_WHITE[UP_WHITE.size()-2],UP_WHITE[UP_WHITE.size()-1],white[i]) == false)UP_WHITE.pop_back();
			UP_WHITE.push_back(white[i]);
		}

		for(int i = num_white-3; i >= 0; i--){
			while(DOWN_WHITE.size() > 1 && calcGaiseki(DOWN_WHITE[DOWN_WHITE.size()-2],DOWN_WHITE[DOWN_WHITE.size()-1],white[i]) == false){
				DOWN_WHITE.pop_back();
			}
			DOWN_WHITE.push_back(white[i]);
		}
	}

	Polygon g_white;

	for(int i = DOWN_WHITE.size()-1; i >= 1;i--)g_white.push_back(DOWN_WHITE[i]);
	for(int i = UP_WHITE.size()-1; i >= 1 ;i--)g_white.push_back(UP_WHITE[i]);

	if(g_black.size() > 1){
		for(int i = 0; i < num_white; i++){
			if(contains(g_black,white[i]) != 0){
				printf("NO\n");
				return;
			}
		}
	}

	if(g_white.size() > 1){
		for(int i = 0; i < num_black; i++){
			if(contains(g_white,black[i]) != 0){
				printf("NO\n");
				return;
			}
		}
	}

	if(intersect(g_black,g_white)){
		printf("NO\n");
	}else{
		printf("YES\n");
	}
}

int main(){

	while(true){
		scanf("%d %d",&num_black,&num_white);
		if(num_black == 0 && num_white == 0)break;

		func();
	}

	return 0;
}



Measured memory_bytes: 3228