Problem:
Problem H:
Monster Trap
Once upon a time when people still believed in magic, there was a great wizard Aranyaka
Gondlir. After twenty years of hard training in a deep forest, he had finally mastered ultimate
magic, and decided to leave the forest for his home.
Arriving at his home village, Aranyaka was very surprised at the extraordinary desolation. A
gloom had settled over the village. Even the whisper of the wind could scare villagers. It was a
mere shadow of what it had been.
What had happened? Soon he recognized a sure sign of an evil monster that is immortal. Even
the great wizard could not kill it, and so he resolved to seal it with magic. Aranyaka could cast
a spell to create a monster trap: once he had drawn a line on the ground with his magic rod,
the line would function as a barrier wall that any monster could not get over. Since he could
only draw straight lines, he had to draw several lines to complete a monster trap, i.e., magic
barrier walls enclosing the monster. If there was a gap between barrier walls, the monster could
easily run away through the gap.
For instance, a complete monster trap without any gaps is built by the barrier walls in the left
figure, where “M” indicates the position of the monster. In contrast, the barrier walls in the
right figure have a loophole, even though it is almost complete.
Your mission is to write a program to tell whether or not the wizard has successfully sealed the
monster.
Input
The input consists of multiple data sets, each in the following format.
n
x
1
y
1
x'
1
y'
1
x
2
y
2
x'
2
y'
2
...
x
n
y
n
x'
n
y'
n
The first line of a data set contains a positive integer n, which is the number of the line segments
drawn by the wizard. Each of the following
n
input lines contains four integers
x
,
y
,
x'
, and
y'
, which represent the
x
- and
y
-coordinates of two points (
x
,
y
) and (
x'
,
y'
) connected by a line
segment. You may assume that all line segments have non-zero lengths. You may also assume
that
n
is less than or equal to 100 and that all coordinates are between -50 and 50, inclusive.
For your convenience, the coordinate system is arranged so that the monster is always on the
origin (0, 0). The wizard never draws lines crossing (0, 0).
You may assume that any two line segments have at most one intersection point and that no
three line segments share the same intersection point. You may also assume that the distance
between any two intersection points is greater than 10
-5
.
An input line containing a zero indicates the end of the input.
Output
For each data set, print “yes” or “no” in a line. If a monster trap is completed, print “yes”.
Otherwise, i.e., if there is a loophole, print “no”.
Sample Input
8
-7 9 6 9
-5 5 6 5
-10 -5 10 -5
-6 9 -9 -6
6 9 9 -6
-1 -2 -3 10
1 -2 3 10
-2 -3 2 -3
8
-7 9 5 7
-5 5 6 5
-10 -5 10 -5
-6 9 -9 -6
6 9 9 -6
-1 -2 -3 10
1 -2 3 10
-2 -3 2 -3
0
Output for the Sample Input
yes
no

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double mini = BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad;
		if(ccw(now,pre_p,next) == CLOCKWISE){

			tmp_rad = calc_rad(now,next,pre_p);
			tmp_rad = 2*M_PI-tmp_rad;
		}else{

			tmp_rad = calc_rad(now,pre_p,next);
		}


		if(mini > tmp_rad+EPS){

			mini = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	if(SET.count(next) > 0){

		EDGES.push_back(next_e_ind);

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}

	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 11348
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double mini = BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad;
		if(ccw(now,pre_p,next) == CLOCKWISE){

			tmp_rad = calc_rad(now,next,pre_p);
			tmp_rad = 2*M_PI-tmp_rad;
		}else{

			tmp_rad = calc_rad(now,pre_p,next);
		}


		if(mini > tmp_rad+EPS){

			mini = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	if(SET.count(next) > 0){

		EDGES.push_back(next_e_ind);

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}

	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		vector<pair<double,int>> work;

		for(int k = 0; k < G[i].size(); k++){

			Point adj = point[G[i][k]]-point[i]; //■注意
			double tmp_rad = calc_rad(adj);
			work.push_back(make_pair(tmp_rad,k));
		}

		sort(work.begin(),work.end());

		int mini_ind = work[0].second;
		int maxi_ind = work.back().second;

		for(int k = 0; k < G[i].size(); k++){
			if(k != mini_ind && k != maxi_ind)continue; //■■最も外側の隣接でないならSKIP

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 11396
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	if(SET.count(next) > 0){

		EDGES.push_back(next_e_ind);

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}

	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		vector<pair<double,int>> work;

		for(int k = 0; k < G[i].size(); k++){

			Point adj = point[G[i][k]]-point[i]; //■注意
			double tmp_rad = calc_rad(adj);
			work.push_back(make_pair(tmp_rad,k));
		}

		sort(work.begin(),work.end());

		int mini_ind = work[0].second;
		int maxi_ind = work.back().second;

		for(int k = 0; k < G[i].size(); k++){
			if(k != mini_ind && k != maxi_ind)continue; //■■最も外側の隣接でないならSKIP

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 170
memory_kb: 11384
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	if(SET.count(next) > 0){

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}

	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	//EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		vector<pair<double,int>> work;

		for(int k = 0; k < G[i].size(); k++){

			Point adj = point[G[i][k]]-point[i]; //■注意
			double tmp_rad = calc_rad(adj);
			work.push_back(make_pair(tmp_rad,k));
		}

		sort(work.begin(),work.end());

		int mini_ind = work[0].second;
		int maxi_ind = work.back().second;

		for(int k = 0; k < G[i].size(); k++){
			if(k != mini_ind && k != maxi_ind)continue; //■■最も外側の隣接でないならSKIP

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 360
memory_kb: 11244
final_rank: 9

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	if(SET.count(next) > 0){

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}
	int next_e_ind = MAP[make_pair(node,G[node][ind])];
	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		vector<pair<double,int>> work;

		for(int k = 0; k < G[i].size(); k++){

			Point adj = point[G[i][k]]-point[i]; //■注意
			double tmp_rad = calc_rad(adj);
			work.push_back(make_pair(tmp_rad,k));
		}

		sort(work.begin(),work.end());

		int mini_ind = work[0].second;
		int maxi_ind = work.back().second;

		for(int k = 0; k < G[i].size(); k++){
			if(k != mini_ind && k != maxi_ind)continue; //■■最も外側の隣接でないならSKIP

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 11368
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	if(SET.count(next) > 0){

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}
	int next_e_ind = MAP[make_pair(node,G[node][ind])];
	if(visited[next_e_ind])return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		vector<pair<double,int>> work;

		for(int k = 0; k < G[i].size(); k++){

			Point adj = point[G[i][k]];
			double tmp_rad = calc_rad(adj);
			work.push_back(make_pair(tmp_rad,k));
		}

		sort(work.begin(),work.end());

		int mini_ind = work[0].second;
		int maxi_ind = work.back().second;

		for(int k = 0; k < G[i].size(); k++){
			if(k != mini_ind && k != maxi_ind)continue; //■■最も外側の隣接でないならSKIP

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 11380
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	if(SET.count(next) > 0){

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}


	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			//■辺に向きをつける
			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 480
memory_kb: 11280
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


/*
 * ■辺始まり辺終わりにするとWAする
 *   点始まり点終わりにする、ただし途中で訪問した辺は再訪しない■*
 * */
void dfs(int pre,int node){

	if(CATCH)return;

	/*if(node == start && pre != start){

		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		CATCH = true;
		return;
	}*/

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next = G[node][ind];
	if(SET.count(next) > 0){

		CATCH = true;
		//図形が完成した場合、訪問済みの辺は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		Polygon work;
		//■■最初にnextに到達するまでの点は削除する
		bool FLG = false;
		for(int i = 0; i < POL.size(); i++){
			if(POL[i] == point[next]){

				FLG = true;
			}
			if(!FLG)continue;

			work.push_back(POL[i]);
		}

		POL.clear();
		POL = work;

		return;
	}


	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(node,G[node][ind]);
}

void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 480
memory_kb: 11164
final_rank: 11

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 30005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE],EDGES;
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];
map<int,pair<int,int>> REV;



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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


void dfs(int start,int pre,int node){

	if(CATCH)return;

	if(node == start && pre != start){

		//図形が完成した場合、訪問済みの両端点は再訪しない
		for(int i = 0; i < EDGES.size(); i++){

			visited[EDGES[i]] = true;
		}

		CATCH = true;
		return;
	}

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		if(adj != start && SET.count(adj) > 0)continue;
		if(adj == start && pre == start)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	int next_e_ind = MAP[make_pair(node,G[node][ind])];

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	EDGES.push_back(next_e_ind);
	dfs(start,node,G[node][ind]);
}

void func(){

	int num_point = 0;
	numE = 0;

	MAP.clear();
	REV.clear();

	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
		visited[i] = false;
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			REV[numE] = make_pair(p,q);
			MAP[make_pair(p,q)] = numE++;

			REV[numE] = make_pair(q,p);
			MAP[make_pair(q,p)] = numE++;

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			int e_ind = MAP[make_pair(i,G[i][k])];
			if(visited[e_ind])continue;

			POL.clear();
			SET.clear();
			EDGES.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			EDGES.push_back(e_ind);

			CATCH = false;
			dfs(i,i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 3750
memory_kb: 12288
final_rank: 20

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 10005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE],ON_SEG[SIZE],CONTAIN[SIZE];
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE],visited[SIZE];
map<pair<int,int>,int> MAP;
int numE = 0,numDEG[SIZE];


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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


void dfs(int start,int pre,int node){

	if(CATCH)return;

	if(node == start && pre != start){

		CATCH = true;
		return;
	}

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		if(adj != start && SET.count(adj) > 0)continue;
		if(adj == start && pre == start)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	dfs(start,node,G[node][ind]);
}

void func(){

	int num_point = 0;
	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
		ON_SEG[i].clear();
		CONTAIN[i].clear();
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//辺が持つ点の番号を保存
			CONTAIN[i].push_back(num_point);
			CONTAIN[k].push_back(num_point);

			//どの辺の上に乗っているか
			ON_SEG[num_point].push_back(i);
			ON_SEG[num_point].push_back(k);

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}


	//■■交点数が1なら行き止まりなので点を削除
	queue<int> que;

	for(int i = 0; i < N; i++){

		numDEG[i] = V[i].size();

		if(numDEG[i] == 1){

			int ind = CONTAIN[i][0];

			DEL[ind] = true; //点を削除
			que.push(ind);
			numDEG[i] = 0;
		}
	}

	while(!que.empty()){

		int ind = que.front(); //消す点番号
		que.pop();

		for(int k = 0; k < ON_SEG[ind].size(); k++){

			int seg = ON_SEG[ind][k]; //消す点が含まれている辺番号
			if(numDEG[seg] == 0)continue;

			numDEG[seg]--;
			if(numDEG[seg] == 1){ //■次数が0になった
				for(int a = 0; a < CONTAIN[seg].size(); a++){ //残っている1点を探す

					int tmp_ind = CONTAIN[seg][a]; //点番号
					if(DEL[tmp_ind])continue;

					DEL[tmp_ind] = true;
					numDEG[seg] = 0;
					que.push(tmp_ind);

					break;
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec; //点番号を並び順に格納

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}
			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		if(work.size() == 0)continue;

		for(int k = 0; k < work.size()-1; k++){

			int p = work[k];
			int q = work[k+1];

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			POL.clear();
			SET.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			CATCH = false;
			dfs(i,i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 6590
memory_kb: 5680
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 10005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE];
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE];


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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}


void dfs(int start,int pre,int node){

	if(CATCH)return;

	if(node == start && pre != start){

		CATCH = true;
		return;
	}

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		if(adj != start && SET.count(adj) > 0)continue;
		if(adj == start && pre == start)continue;

		Point next = point[adj];

		double tmp_rad = calc_rad(now,pre_p,next);

		if(maxi+EPS < tmp_rad){

			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	dfs(start,node,G[node][ind]);
}

void func(){

	int num_point = 0;
	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}
	//■■交点数が1なら行き止まりなので点を削除
	for(int i = 0; i < N; i++){
		if(V[i].size() == 1){

			int ind = -1;
			for(int k = 0; k < num_point; k++){
				if(point[k] == V[i][0]){

					ind = k;
					break;
				}
			}

			DEL[ind] = true;
		}
	}

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		vector<int> vec;

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}

			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		vec = work;

		for(int k = 0; k < vec.size()-1; k++){

			int p = vec[k];
			int q = vec[k+1];

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			POL.clear();
			SET.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			CATCH = false;
			dfs(i,i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 6550
memory_kb: 5016
final_rank: 18

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
#define chmin(x,y) x = min(x,y)
#define chmax(x,y) x = max(x,y)
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 998244353
//#define MOD 1000000007
#define EPS 0.000000001



#define SIZE 10005


struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	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 &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

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


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};


typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	/*void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}*/
	Point p[2];
};


int N;
Line line[SIZE];
Point point[SIZE];
vector<Point> V[SIZE];
vector<int> G[SIZE];
set<int> SET;
Polygon POL;
bool CATCH,DEL[SIZE];


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

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

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

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;
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

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

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

    return ret;
}

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


//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

/*
 * 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);
}

//2つのvectorがなすラジアンを求める関数
double calc_rad(Vector vec1,Vector vec2){

	double tmp = dot(vec1,vec2)/(abs(vec1)*abs(vec2));

	if(fabs(tmp+1.0) < EPS){

		return M_PI;
	}

	if(fabs(tmp-1.0) < EPS){

		return  0.0;
	}

	return acos(dot(vec1,vec2)/(abs(vec1)*abs(vec2)));
}

//3点がなすラジアンを求める関数(ccw(base,a,b) == CCW)
double calc_rad(Point base,Point a,Point b){

	Vector vec1 = b-base;
	Vector vec2 = a-base;

	return calc_rad(vec1,vec2);
}

bool DEBUG = false;


void dfs(int start,int pre,int node){

	if(CATCH)return;

	if(DEBUG){

		printf("start:%d pre:%d node:%d ■現在の座標\n",start,pre,node);
		point[node].debug();
	}

	if(node == start && pre != start){

		CATCH = true;
		if(DEBUG){
			printf("■■とらえた\n");
			printf("start: [%d] ",start);
			point[start].debug();
			printf("pre: [%d]  ",pre);
			point[pre].debug();
		}
		return;
	}

	Point pre_p = point[pre];
	Point now = point[node];

	double maxi = -BIG_NUM;
	int ind = -1;

	for(int i = 0; i < G[node].size(); i++){
		int adj = G[node][i];
		if(adj == pre)continue;

		if(adj != start && SET.count(adj) > 0)continue;
		if(adj == start && pre == start)continue;

		Point next = point[adj];

		//if(ccw(now,next,pre_p) == CLOCKWISE)continue;


		double tmp_rad = calc_rad(now,pre_p,next);
		//printf("tmp_rad:%.3lf\n",tmp_rad);
		if(maxi+EPS < tmp_rad){

			//printf("tmp_rad:%.3lf\n",tmp_rad);
			maxi = tmp_rad;
			ind = i;
		}
	}

	if(ind == -1)return;

	SET.insert(G[node][ind]);
	POL.push_back(point[G[node][ind]]);
	dfs(start,node,G[node][ind]);
}

void func(){

	int num_point = 0;
	for(int i = 0; i < SIZE; i++){

		V[i].clear();
		G[i].clear();
	}

	Point base = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf %lf %lf",&line[i].p[0].x,&line[i].p[0].y,&line[i].p[1].x,&line[i].p[1].y);
	}

	//交点を全列挙
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(!is_Cross(line[i],line[k]))continue;

			Point cross_p = calc_Cross_Point(line[i],line[k]);

			bool FLG = true;
			for(int a = 0; a < num_point; a++){
				if(point[a] == cross_p){

					FLG = false;
					break;
				}
			}
			if(!FLG)continue;

			//cross_p.debug();

			point[num_point++] = cross_p;
			V[i].push_back(cross_p);
			V[k].push_back(cross_p);
		}
	}

	for(int i = 0; i < num_point; i++){

		DEL[i] = false;
	}
	//交点数が1なら行き止まりなので点を削除
	for(int i = 0; i < N; i++){
		if(V[i].size() == 1){

			int ind = -1;
			for(int k = 0; k < num_point; k++){
				if(point[k] == V[i][0]){

					ind = k;
					break;
				}
			}

			DEL[ind] = true;
		}
	}

/*
	for(int i = 0; i < num_point; i++){

		printf("点%d ",i);
		point[i].debug();
	}*/

	for(int i = 0; i < N; i++){
		if(V[i].size() <= 1)continue;

		sort(V[i].begin(),V[i].end());

		/*printf("\n線分%d",i);
		for(int a = 0; a < V[i].size(); a++){

			V[i][a].debug();
		}*/

		vector<int> vec;

		for(int k = 0; k < V[i].size(); k++){
			int ind = -1;
			for(int a = 0; a < num_point; a++){
				if(point[a] == V[i][k]){

					ind = a;
					break;
				}
			}

			vec.push_back(ind);
		}

		vector<int> work;
		for(int k = 0; k < vec.size(); k++){
			if(!DEL[vec[k]]){

				work.push_back(vec[k]);
			}
		}

		vec = work;

		for(int k = 0; k < vec.size()-1; k++){

			int p = vec[k];
			int q = vec[k+1];

			G[p].push_back(q);
			G[q].push_back(p);
		}
	}
/*
	for(int i = 0; i < num_point; i++){
		//f(i != 0 && i != 1)continue;

		printf("\n点%dです\n",i);
		for(int k = 0; k < G[i].size(); k++){

			printf("点%dと隣接\n",G[i][k]);
		}
	}
	return;*/

	for(int i = 0; i < num_point; i++){
		if(G[i].size() == 0)continue;

		for(int k = 0; k < G[i].size(); k++){

			POL.clear();
			SET.clear();

			POL.push_back(point[i]);
			POL.push_back(point[G[i][k]]);

			SET.insert(i);
			SET.insert(G[i][k]); //最初の2点を全探索

			if(DEBUG){
				printf("\n◎◎◎dfs\n");
			}

			CATCH = false;
			dfs(i,i,G[i][k]);
			if(CATCH){


				if(contains(POL,base) == 2){

					if(DEBUG){
						for(int a = 0; a < POL.size(); a++){

							POL[a].debug();
						}
					}

					printf("yes\n");
					return;
				}
			}
		}
	}
	printf("no\n");
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 6560
memory_kb: 4848
final_rank: 17

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
#include"bits/stdc++.h"

using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,m,n) for(int i=(m);i<(n);i++)

const bool DEBUG = false;

const double EPS = 1e-8;
typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
	double a, b;
	is >> a >> b;
	p = point(a, b);
	return is;
}
point operator*(const point&p, const double &d) {
	return point(real(p)*d, imag(p)*d);
}
namespace std {
	bool operator < (const point& a, const point& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

//直線or線分
struct Line : public vector<point> {
	Line(const point &a, const point &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<Line>Lines;


double cross(const point& a, const point& b) {
	return real(a)*imag(b) - imag(a)*real(b);
}
double dot(const point& a, const point& b) {
	return real(a)*real(b) + imag(a)*imag(b);
}
int ccw(point a, point b, point c) {
	b = b - a; c = c - a;
	if (cross(b, c) > EPS)   return +1;       // counter clockwise
	if (cross(b, c) < -EPS)   return -1;       // clockwise
	if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
	return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS || //non-parallel
		abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS; //same line
}
bool intersectLS(const Line &l, const Line &s) {
	return cross(l[1] - l[0], s[0] - l[0])* // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
	if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS)return false;
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}

bool intersectSP(const Line &s, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}
bool connectSS(const Line &s, const Line &t) {
	if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))return true;
	else return false;
}
bool isSamePoint(const point &p1, const point &p2) {
	return abs(p1 - p2)<EPS;
}
bool connectSS_with_endpoint(const Line &s, const Line &t) {
	REP(i, 2)REP(j, 2) {
		//if(isSamePoint(s[i],t[j]))return true;
		if (s[i] == t[j])return true;
	}
	return false;
}
bool intersectSS(const Line &s, const Line &t) {
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}
bool intersectSS_strict(const Line &s, const Line &t) {
	//端点が線分上に乗っている場合はfalseにする
	if (connectSS(s, t))return false;
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}

bool isOn(const Line &l, const point &p) {
	if (l[0] == p || l[1] == p)return false;
	point d = l[1] - l[0];
	point p0 = (p - l[0]) / d;
	return p0.imag() == 0.0&&0.0<p0.real() && p0.real()<1.0;
}
bool intersect(const Line &l0, const Line &l1, point &p) {
	if (connectSS_with_endpoint(l0, l1) || isOn(l0, l1[0]) || isOn(l0, l1[1]) || isOn(l1, l0[0]) || isOn(l1, l0[1]))return false;
	point d = l0[1] - l0[0];
	point p0 = (l1[0] - l0[0]) / d;
	point p1 = (l1[1] - l0[0]) / d;
	if (p0.imag()*p1.imag() >= 0)return false;
	double t = p0.imag() / (p0.imag() - p1.imag());
	double s = p0.real()*(1 - t) + p1.real()*t;
	if (s <= 0.0 || 1.0 <= s)return false;
	p = l0[0] + d * s;
	return true;
}

//距離,交点
//射影 直線lにpから下した垂線との交点

point projection(const Line &l, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1])*t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) {
	return p + (projection(l, p) - p) * 2;
}
double distancePP(const point& a, const point& b) {
	return sqrt(norm(a - b));
}
double distanceLP(const Line &l, const point &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const Line&l, const Line &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
	if (intersectLS(l, s))return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
	const point r = projection(s, p);
	if (intersectSP(s, r))return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	if (intersectSS(s, t))return 0;
	return min({ distanceSP(s,t[0]),distanceSP(s,t[1]),distanceSP(t,s[0]),distanceSP(t,s[1]) });
}
point crosspoint(const Line &l, const Line &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS&&abs(B) < EPS)return m[0];//same line
	if (abs(A) < EPS)assert(false); // Precondition not satisfied
	return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) {
	return abs(p1 - p2);
}

//線分同士の交点で分割して端点以外の共有点を持たないようにする
void splitSegments(Lines &ls) {
	//端点が線分上に乗っている場合の分割
	for (int i = 0; i < (int)ls.size(); i++){
		int mx = ls.size();
		for (int j = i + 1; j < (int)ls.size(); j++) {
			if (j >= mx)break;
			for (int k = 0; k < 2; k++) {
				//if(isOn(ls[i],ls[j][k])){
				if (intersectSP_without_endpoint(ls[i], ls[j][k])) {
					ls.push_back(Line(ls[i][0], ls[j][k]));
					ls[i][0] = ls[j][k];
					break;
				}
				//else if(isOn(ls[j],ls[i][k])){
				else if (intersectSP_without_endpoint(ls[j], ls[i][k])) {
					ls.push_back(Line(ls[j][0], ls[i][k]));
					ls[j][0] = ls[i][k];
					break;
				}
			}
		}
	}
	//cerr << "split-1" << endl;
	//線分が交差している場合の分割
	for (int i = 0; i < (int)ls.size(); i++) {
		Line li = ls[i];
		int mx = ls.size();
		for (int j = i + 1; j < (int)ls.size(); j++) {
			point cross_p;
			if (j >= mx)break;
			//if (intersect(ls[i], ls[j], cross_p)) {
			if (intersectSS_strict(ls[i], ls[j])) {
				cross_p = crosspoint(ls[i], ls[j]);
				ls.push_back(Line(ls[i][0], cross_p));
				ls[i][0] = cross_p;
				ls.push_back(Line(ls[j][0], cross_p));
				ls[j][0] = cross_p;
			}
		}
	}
}

//線分の集合(split済み)を連結成分に分解する(union-find)

struct Equiv {
	vector<int>links;
	//大きさ1の同値類をn個作る
	Equiv(int n) :links(n) {
		for (int i = 0; i < n; i++) {
			links[i] = i;
		}
	}
	//xの属する同値類の代表元を返す
	int find(int x) {
		int xx = links[x];
		if (xx == x)return x;
		return links[x] = find(xx);
	}
	void unify(int x, int y) {
		int xx = find(x), yy = find(y);
		if (xx <= yy)links[yy] = xx;
		else links[xx] = yy;
	}
};

typedef vector<Lines>vLines;
vLines connectedComponent(const Lines &ls) {
	vLines ret;
	Equiv equiv(ls.size());
	for (int i = 0; i < (int)ls.size(); i++) {
		for (int j = 0; j < i; j++) {
			if (connectSS_with_endpoint(ls[i], ls[j])) {
				equiv.unify(i, j);
			}
		}
	}
	//cerr << "connected-1" << endl;
	for (int i = 0; i < (int)ls.size(); i++) {
		if (equiv.find(i) == i) {
			Lines newLs;
			newLs.push_back(ls[i]);
			for (int j = i + 1; j < (int)ls.size(); j++) {
				if (equiv.find(j) == i)newLs.push_back(ls[j]);
			}
			ret.push_back(newLs);
		}
	}
	return ret;
}
//左手法でのトレース
//偏角でソートされた隣接点のvectorを得る
typedef pair<double, point>doublePoint;
typedef vector<doublePoint> vDoublePoint;
typedef map<point, vDoublePoint> adjPoint;
typedef vector<point>points;
//移動前の点と隣接点のリストから移動先を決定
point findNext(const vDoublePoint &vdp, const point &p) {
	for (int i = 0; i < (int)vdp.size() - 1; i++) {
		if (p == vdp[i].second) {
			return vdp[i + 1].second;
		}
	}
	return vdp[0].second;
}
//左手法でトレースして通った点の列を返す
points trace(const Lines &ls) {
	adjPoint aPoint;
	//隣接点(偏角付き)のリストを作成
	for (int i = 0; i < (int)ls.size(); i++) {
		aPoint[ls[i][0]].push_back(doublePoint(arg(ls[i][1] - ls[i][0]), ls[i][1]));
		aPoint[ls[i][1]].push_back(doublePoint(arg(ls[i][0] - ls[i][1]), ls[i][0]));
	}
	//x座標最小の点の計算と隣接点リストのソート
	point minPoint(INT_MAX, INT_MAX);
	adjPoint::iterator it;
	for (it = aPoint.begin(); it != aPoint.end(); ++it) {
		point p = it->first;
		minPoint = min(minPoint, p);
		vDoublePoint &vdp = it->second;
		sort(vdp.begin(), vdp.end());
	}
	points ret;
	ret.push_back(minPoint);
	//最初の移動先
	point curP = aPoint[minPoint][0].second;
	point lastP = minPoint;
	//トレースの繰り返し
	while (curP != minPoint) {
		if (DEBUG)cerr << curP << endl;
		ret.push_back(curP);
		point nextP = findNext(aPoint[curP], lastP);
		//if(isSamePoint(curP,nextP))break;
		lastP = curP;
		curP = nextP;
	}
	//開始点を最後にも追加
	ret.push_back(minPoint);
	return ret;
}

bool isInside(const points &ps) {
	Line l0(point(0, 0), point(51.0, 1.0 / 20000.0));
	int count = 0;
	for (int i = 0; i < (int)ps.size() - 1; i++) {
		point dummy;
		Line l1(ps[i], ps[i + 1]);
		if (intersect(l0, l1, dummy))count++;
	}
	return (count & 1) == 1;
}


//円
struct Circle {
	point p; double r;
	Circle(const point &p_, double r_) : p(p_), r(r_) { }
};

//凸包
vector<point> convex_hull(vector<point> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<point> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

//2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
	double d = dist(p1, p2);
	double x1 = p1.real(), x2 = p2.real();
	double y1 = p1.imag(), y2 = p2.imag();
	if (p1.imag() == p2.imag()) {
		double x = (x1 + x2) / 2.0;
		double dy = sqrt(R - d * d / 4);
		return { { x,y1 + dy },{ x,y1 - dy } };
	}
	else {
		double m = (x1 - x2) / (y2 - y1);
		double t = sqrt(R*R - d * d / 4);
		double dx = sqrt((t*t) / (m*m + 1));
		double dy = sqrt(t*t - dx * dx);
		double gx = (x1 + x2) / 2;
		double gy = (y1 + y2) / 2;
		if (m > EPS) {
			return { { gx + dx,gy + dy },{ gx - dx,gy - dy } };
		}
		else {
			return { { gx + dx,gy - dy },{ gx - dx,gy + dy } };
		}
	}
}
//長方形
struct Square {
	double lx, ly, rx, ry;
	Square(double lx_, double ly_, double rx_, double ry_) :lx(lx_), ly(ly_), rx(rx_), ry(ry_) {};
	bool include(point &p) {
		return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
	}
};

struct Polygon : public vector<point> {
	//0->OUT, 1->ON, 2->IN
	int contains(const point &p) {
		bool in = false;
		int N = this->size();
		for (int i = 0; i < N; i++) {
			point a = this->at(i) - p;
			point b = this->at((i + 1) % N) - p;
			if (imag(a) > imag(b)) {
				std::swap(a, b);
			}
			if (imag(a) <= 0 && 0 < imag(b))
				if (cross(a, b) < 0)in = !in;
			if (cross(a, b) == 0 && dot(a, b) <= 0)return 1;
		}
		return in ? 2 : 0;
	}
};
clock_t START, END;
bool trapAll() {
	int N; cin >> N;
	if (N == 0) {
		END = clock();
		double t = (double)(END - START) / CLOCKS_PER_SEC;
		//cerr << "elapsed time" << t << "[sec]" << endl;
		exit(0);
	}
	Lines ls;
	REP(i, N) {
		double x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		point p1(x1, y1);
		point p2(x2, y2);
		ls.push_back(Line(p1, p2));
	}
	splitSegments(ls);
	// for(auto l:ls){
	// 	cerr<<l[0]<<" "<<l[1]<<endl;
	// }
	//cerr << "splitted" << endl;
	vLines vls = connectedComponent(ls);
	for (auto lines : vls) {
		//if(isInside(trace(lines)))return true;
		Polygon poly;
		points ps = trace(lines);
		for (auto p : ps) {
			poly.push_back(p);
		}
		if (poly.contains(point(0, 0)))return true;
	}
	return false;
}

void solve() {
	if (trapAll())cout << "yes" << endl;
	else cout << "no" << endl;
	if (DEBUG)cerr << "+++++++++++++" << endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	START = clock();
	while (true)
		solve();

}
accuracy: 1
time_ms: 3930
memory_kb: 6452
final_rank: 10

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
#include"bits/stdc++.h"

using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,m,n) for(int i=(m);i<(n);i++)

const bool DEBUG = false;

const double EPS = 1e-8;
typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
	double a, b;
	is >> a >> b;
	p = point(a, b);
	return is;
}
point operator*(const point&p, const double &d) {
	return point(real(p)*d, imag(p)*d);
}
namespace std {
	bool operator < (const point& a, const point& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

//直線or線分
struct Line : public vector<point> {
	Line(const point &a, const point &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<Line>Lines;


double cross(const point& a, const point& b) {
	return real(a)*imag(b) - imag(a)*real(b);
}
double dot(const point& a, const point& b) {
	return real(a)*real(b) + imag(a)*imag(b);
}
int ccw(point a, point b, point c) {
	b = b - a; c = c - a;
	if (cross(b, c) > EPS)   return +1;       // counter clockwise
	if (cross(b, c) < -EPS)   return -1;       // clockwise
	if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
	return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS || //non-parallel
		abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS; //same line
}
bool intersectLS(const Line &l, const Line &s) {
	return cross(l[1] - l[0], s[0] - l[0])* // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
	if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS)return false;
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}

bool intersectSP(const Line &s, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}
bool connectSS(const Line &s, const Line &t) {
	if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))return true;
	else return false;
}
bool isSamePoint(const point &p1, const point &p2) {
	return abs(p1 - p2)<EPS;
}
bool connectSS_with_endpoint(const Line &s, const Line &t) {
	REP(i, 2)REP(j, 2) {
		//if(isSamePoint(s[i],t[j]))return true;
		if (s[i] == t[j])return true;
	}
	return false;
}
bool intersectSS(const Line &s, const Line &t) {
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}
bool intersectSS_strict(const Line &s, const Line &t) {
	//端点が線分上に乗っている場合はfalseにする
	if (connectSS(s, t))return false;
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}

bool isOn(const Line &l, const point &p) {
	if (l[0] == p || l[1] == p)return false;
	point d = l[1] - l[0];
	point p0 = (p - l[0]) / d;
	return p0.imag() == 0.0&&0.0<p0.real() && p0.real()<1.0;
}
bool intersect(const Line &l0, const Line &l1, point &p) {
	if (connectSS_with_endpoint(l0, l1) || isOn(l0, l1[0]) || isOn(l0, l1[1]) || isOn(l1, l0[0]) || isOn(l1, l0[1]))return false;
	point d = l0[1] - l0[0];
	point p0 = (l1[0] - l0[0]) / d;
	point p1 = (l1[1] - l0[0]) / d;
	if (p0.imag()*p1.imag() >= 0)return false;
	double t = p0.imag() / (p0.imag() - p1.imag());
	double s = p0.real()*(1 - t) + p1.real()*t;
	if (s <= 0.0 || 1.0 <= s)return false;
	p = l0[0] + d * s;
	return true;
}

//距離,交点
//射影 直線lにpから下した垂線との交点

point projection(const Line &l, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1])*t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) {
	return p + (projection(l, p) - p) * 2;
}
double distancePP(const point& a, const point& b) {
	return sqrt(norm(a - b));
}
double distanceLP(const Line &l, const point &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const Line&l, const Line &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
	if (intersectLS(l, s))return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
	const point r = projection(s, p);
	if (intersectSP(s, r))return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	if (intersectSS(s, t))return 0;
	return min({ distanceSP(s,t[0]),distanceSP(s,t[1]),distanceSP(t,s[0]),distanceSP(t,s[1]) });
}
point crosspoint(const Line &l, const Line &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS&&abs(B) < EPS)return m[0];//same line
	if (abs(A) < EPS)assert(false); // Precondition not satisfied
	return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) {
	return abs(p1 - p2);
}

//線分同士の交点で分割して端点以外の共有点を持たないようにする
void splitSegments(Lines &ls) {
	//端点が線分上に乗っている場合の分割
	for (int i = 0; i < (int)ls.size(); i++){
		int mx = ls.size();
		for (int j = i + 1; j < (int)ls.size(); j++) {
			if (j >= mx)break;
			for (int k = 0; k < 2; k++) {
				//if(isOn(ls[i],ls[j][k])){
				if (intersectSP_without_endpoint(ls[i], ls[j][k])) {
					ls.push_back(Line(ls[i][0], ls[j][k]));
					ls[i][0] = ls[j][k];
					break;
				}
				//else if(isOn(ls[j],ls[i][k])){
				else if (intersectSP_without_endpoint(ls[j], ls[i][k])) {
					ls.push_back(Line(ls[j][0], ls[i][k]));
					ls[j][0] = ls[i][k];
					break;
				}
			}
		}
	}
	//cerr << "split-1" << endl;
	//線分が交差している場合の分割
	for (int i = 0; i < (int)ls.size(); i++) {
		Line li = ls[i];
		int mx = ls.size();
		for (int j = i + 1; j < (int)ls.size(); j++) {
			point cross_p;
			if (j >= mx)break;
			if (intersect(ls[i], ls[j], cross_p)) {
				//if (intersectSS_strict(ls[i], ls[j])) {
				//point cross_p = crosspoint(ls[i], ls[j]);
				ls.push_back(Line(ls[i][0], cross_p));
				ls[i][0] = cross_p;
				ls.push_back(Line(ls[j][0], cross_p));
				ls[j][0] = cross_p;
			}
		}
	}
}

//線分の集合(split済み)を連結成分に分解する(union-find)

struct Equiv {
	vector<int>links;
	//大きさ1の同値類をn個作る
	Equiv(int n) :links(n) {
		for (int i = 0; i < n; i++) {
			links[i] = i;
		}
	}
	//xの属する同値類の代表元を返す
	int find(int x) {
		int xx = links[x];
		if (xx == x)return x;
		return links[x] = find(xx);
	}
	void unify(int x, int y) {
		int xx = find(x), yy = find(y);
		if (xx <= yy)links[yy] = xx;
		else links[xx] = yy;
	}
};

typedef vector<Lines>vLines;
vLines connectedComponent(const Lines &ls) {
	vLines ret;
	Equiv equiv(ls.size());
	for (int i = 0; i < (int)ls.size(); i++) {
		for (int j = 0; j < i; j++) {
			if (connectSS_with_endpoint(ls[i], ls[j])) {
				equiv.unify(i, j);
			}
		}
	}
	//cerr << "connected-1" << endl;
	for (int i = 0; i < (int)ls.size(); i++) {
		if (equiv.find(i) == i) {
			Lines newLs;
			newLs.push_back(ls[i]);
			for (int j = i + 1; j < (int)ls.size(); j++) {
				if (equiv.find(j) == i)newLs.push_back(ls[j]);
			}
			ret.push_back(newLs);
		}
	}
	return ret;
}
//左手法でのトレース
//偏角でソートされた隣接点のvectorを得る
typedef pair<double, point>doublePoint;
typedef vector<doublePoint> vDoublePoint;
typedef map<point, vDoublePoint> adjPoint;
typedef vector<point>points;
//移動前の点と隣接点のリストから移動先を決定
point findNext(const vDoublePoint &vdp, const point &p) {
	for (int i = 0; i < (int)vdp.size() - 1; i++) {
		if (p == vdp[i].second) {
			return vdp[i + 1].second;
		}
	}
	return vdp[0].second;
}
//左手法でトレースして通った点の列を返す
points trace(const Lines &ls) {
	adjPoint aPoint;
	//隣接点(偏角付き)のリストを作成
	for (int i = 0; i < (int)ls.size(); i++) {
		aPoint[ls[i][0]].push_back(doublePoint(arg(ls[i][1] - ls[i][0]), ls[i][1]));
		aPoint[ls[i][1]].push_back(doublePoint(arg(ls[i][0] - ls[i][1]), ls[i][0]));
	}
	//x座標最小の点の計算と隣接点リストのソート
	point minPoint(INT_MAX, INT_MAX);
	adjPoint::iterator it;
	for (it = aPoint.begin(); it != aPoint.end(); ++it) {
		point p = it->first;
		minPoint = min(minPoint, p);
		vDoublePoint &vdp = it->second;
		sort(vdp.begin(), vdp.end());
	}
	points ret;
	ret.push_back(minPoint);
	//最初の移動先
	point curP = aPoint[minPoint][0].second;
	point lastP = minPoint;
	//トレースの繰り返し
	while (curP != minPoint) {
		if (DEBUG)cerr << curP << endl;
		ret.push_back(curP);
		point nextP = findNext(aPoint[curP], lastP);
		//if(isSamePoint(curP,nextP))break;
		lastP = curP;
		curP = nextP;
	}
	//開始点を最後にも追加
	ret.push_back(minPoint);
	return ret;
}

bool isInside(const points &ps) {
	Line l0(point(0, 0), point(51.0, 1.0 / 20000.0));
	int count = 0;
	for (int i = 0; i < (int)ps.size() - 1; i++) {
		point dummy;
		Line l1(ps[i], ps[i + 1]);
		if (intersect(l0, l1, dummy))count++;
	}
	return (count & 1) == 1;
}


//円
struct Circle {
	point p; double r;
	Circle(const point &p_, double r_) : p(p_), r(r_) { }
};

//凸包
vector<point> convex_hull(vector<point> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<point> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

//2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
	double d = dist(p1, p2);
	double x1 = p1.real(), x2 = p2.real();
	double y1 = p1.imag(), y2 = p2.imag();
	if (p1.imag() == p2.imag()) {
		double x = (x1 + x2) / 2.0;
		double dy = sqrt(R - d * d / 4);
		return { { x,y1 + dy },{ x,y1 - dy } };
	}
	else {
		double m = (x1 - x2) / (y2 - y1);
		double t = sqrt(R*R - d * d / 4);
		double dx = sqrt((t*t) / (m*m + 1));
		double dy = sqrt(t*t - dx * dx);
		double gx = (x1 + x2) / 2;
		double gy = (y1 + y2) / 2;
		if (m > EPS) {
			return { { gx + dx,gy + dy },{ gx - dx,gy - dy } };
		}
		else {
			return { { gx + dx,gy - dy },{ gx - dx,gy + dy } };
		}
	}
}
//長方形
struct Square {
	double lx, ly, rx, ry;
	Square(double lx_, double ly_, double rx_, double ry_) :lx(lx_), ly(ly_), rx(rx_), ry(ry_) {};
	bool include(point &p) {
		return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
	}
};

struct Polygon : public vector<point> {
	//0->OUT, 1->ON, 2->IN
	int contains(const point &p) {
		bool in = false;
		int N = this->size();
		for (int i = 0; i < N; i++) {
			point a = this->at(i) - p;
			point b = this->at((i + 1) % N) - p;
			if (imag(a) > imag(b)) {
				std::swap(a, b);
			}
			if (imag(a) <= 0 && 0 < imag(b))
				if (cross(a, b) < 0)in = !in;
			if (cross(a, b) == 0 && dot(a, b) <= 0)return 1;
		}
		return in ? 2 : 0;
	}
};
clock_t START, END;
bool trapAll() {
	int N; cin >> N;
	if (N == 0) {
		END = clock();
		double t = (double)(END - START) / CLOCKS_PER_SEC;
		//cerr << "elapsed time" << t << "[sec]" << endl;
		exit(0);
	}
	Lines ls;
	REP(i, N) {
		double x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		point p1(x1, y1);
		point p2(x2, y2);
		ls.push_back(Line(p1, p2));
	}
	splitSegments(ls);
	// for(auto l:ls){
	// 	cerr<<l[0]<<" "<<l[1]<<endl;
	// }
	//cerr << "splitted" << endl;
	vLines vls = connectedComponent(ls);
	for (auto lines : vls) {
		if(isInside(trace(lines)))return true;
		// Polygon poly;
		// points ps = trace(lines);
		// for (auto p : ps) {
		// 	poly.push_back(p);
		// }
		// if (poly.contains(point(0, 0)))return true;
	}
	return false;
}

void solve() {
	if (trapAll())cout << "yes" << endl;
	else cout << "no" << endl;
	if (DEBUG)cerr << "+++++++++++++" << endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	START = clock();
	while (true)
		solve();

}
accuracy: 1
time_ms: 5130
memory_kb: 6292
final_rank: 13

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
#include"bits/stdc++.h"

using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,m,n) for(int i=(m);i<(n);i++)

const bool DEBUG = false;

const double EPS = 1e-8;
typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
  double a, b;
  is >> a >> b;
  p = point(a, b);
  return is;
}
point operator*(const point&p, const double &d) {
	return point(real(p)*d, imag(p)*d);
}
namespace std {
	bool operator < (const point& a, const point& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

//直線or線分
struct Line : public vector<point> {
	Line(const point &a, const point &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<Line>Lines;


double cross(const point& a, const point& b) {
  return real(a)*imag(b)-imag(a)*real(b);
}
double dot(const point& a, const point& b) {
  return real(a)*real(b)+imag(a)*imag(b);
}
int ccw(point a, point b, point c) {
	b =b-a; c =c - a;
	if (cross(b, c) > EPS)   return +1;       // counter clockwise
	if (cross(b, c) < -EPS)   return -1;       // clockwise
	if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
	return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS || //non-parallel
		abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS; //same line
}
bool intersectLS(const Line &l, const Line &s) {
	return cross(l[1] - l[0], s[0] - l[0])* // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
	if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS)return false;
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}

bool intersectSP(const Line &s, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}
bool connectSS(const Line &s, const Line &t) {
	if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))return true;
	else return false;
}
bool isSamePoint(const point &p1,const point &p2){
	return abs(p1-p2)<EPS;
}
bool connectSS_with_endpoint(const Line &s,const Line &t){
	REP(i,2)REP(j,2){
		//if(isSamePoint(s[i],t[j]))return true;
		if(s[i]==t[j])return true;
	}
	return false;
}
bool intersectSS(const Line &s, const Line &t) {
	return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
		ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}
bool intersectSS_strict(const Line &s, const Line &t) {
	//端点が線分上に乗っている場合はfalseにする
	if (connectSS(s, t))return false;
	return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
		ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}

bool isOn(const Line &l,const point &p){
	if(l[0]==p||l[1]==p)return false;
	point d=l[1]-l[0];
	point p0=(p-l[0])/d;
	return p0.imag()==0.0&&0.0<p0.real()&&p0.real()<1.0;
}
bool intersect(const Line &l0,const Line &l1, point &p){
	if(connectSS_with_endpoint(l0,l1)||isOn(l0,l1[0])||isOn(l0,l1[1])||isOn(l1,l0[0])||isOn(l1,l0[1]))return false;
	point d = l0[1]-l0[0];
	point p0=(l1[0]-l0[0])/d;
	point p1=(l1[1]-l0[0])/d;
	if(p0.imag()*p1.imag()>=0)return false;
	double t=p0.imag()/(p0.imag()-p1.imag());
	double s=p0.real()*(1-t)+p1.real()*t;
	if(s<=0.0||1.0<=s)return false;
	p=l0[0]+d*s;
	return true;
}

//距離,交点
//射影 直線lにpから下した垂線との交点

point projection(const Line &l, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1])*t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) {
	return p + (projection(l, p) - p) * 2;
}
double distancePP(const point& a, const point& b) {
	return sqrt(norm(a - b));
}
double distanceLP(const Line &l, const point &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const Line&l, const Line &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
	if (intersectLS(l, s))return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
	const point r = projection(s, p);
	if (intersectSP(s, r))return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	if (intersectSS(s, t))return 0;
	return min({ distanceSP(s,t[0]),distanceSP(s,t[1]),distanceSP(t,s[0]),distanceSP(t,s[1]) });
}
point crosspoint(const Line &l, const Line &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS&&abs(B) < EPS)return m[0];//same line
	if (abs(A) < EPS)assert(false); // Precondition not satisfied
	return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) {
	return abs(p1 - p2);
}

//線分同士の交点で分割して端点以外の共有点を持たないようにする
void splitSegments(Lines &ls) {
	//端点が線分上に乗っている場合の分割
	for (size_t i = 0; i < ls.size(); i++)for (size_t j = i + 1; j < ls.size(); j++) {
		for (int k = 0; k < 2; k++) {
			//if(isOn(ls[i],ls[j][k])){
			if (intersectSP_without_endpoint(ls[i], ls[j][k])) {
				ls.push_back(Line(ls[i][0], ls[j][k]));
				ls[i][0] = ls[j][k];
				break;
			}
			//else if(isOn(ls[j],ls[i][k])){
			else if (intersectSP_without_endpoint(ls[j], ls[i][k])) {
				ls.push_back(Line(ls[j][0], ls[i][k]));
				ls[j][0] = ls[i][k];
				break;
			}
		}
	}
	//cerr << "split-1" << endl;
	//線分が交差している場合の分割
	for (size_t i = 0; i < ls.size(); i++) {
		Line li = ls[i];
		for (size_t j = i + 1; j < ls.size(); j++) {
			point cross_p;
			if(intersect(ls[i],ls[j],cross_p)){
			//if (intersectSS_strict(ls[i], ls[j])) {
				//point cross_p = crosspoint(ls[i], ls[j]);
				ls.push_back(Line(ls[i][0], cross_p));
				ls[i][0] = cross_p;
				ls.push_back(Line(ls[j][0], cross_p));
				ls[j][0] = cross_p;
			}
		}
	}
}

//線分の集合(split済み)を連結成分に分解する(union-find)

struct Equiv {
	vector<int>links;
	//大きさ1の同値類をn個作る
	Equiv(int n):links(n){
		for (int i = 0; i < n; i++) {
			links[i] = i;
		}
	}
	//xの属する同値類の代表元を返す
	int find(int x) {
		int xx = links[x];
		if (xx == x)return x;
		return links[x] = find(xx);
	}
	void unify(int x, int y) {
		int xx = find(x), yy = find(y);
		if (xx <= yy)links[yy] = xx;
		else links[xx] = yy;
	}
};

typedef vector<Lines>vLines;
vLines connectedComponent(const Lines &ls) {
	vLines ret;
	Equiv equiv(ls.size());
	for (int i = 0; i < (int)ls.size(); i++) {
		for (int j = 0; j < i; j++) {
			if (connectSS_with_endpoint(ls[i], ls[j])) {
				equiv.unify(i, j);
			}
		}
	}
	//cerr << "connected-1" << endl;
	for (int i = 0; i < (int)ls.size(); i++) {
		if (equiv.find(i) == i) {
			Lines newLs;
			newLs.push_back(ls[i]);
			for (int j = i + 1; j < (int)ls.size(); j++) {
				if (equiv.find(j) == i)newLs.push_back(ls[j]);
			}
			ret.push_back(newLs);
		}
	}
	return ret;
}
//左手法でのトレース
//偏角でソートされた隣接点のvectorを得る
typedef pair<double, point>doublePoint;
typedef vector<doublePoint> vDoublePoint;
typedef map<point, vDoublePoint> adjPoint;
typedef vector<point>points;
//移動前の点と隣接点のリストから移動先を決定
point findNext(const vDoublePoint &vdp, const point &p) {
	for (int i = 0; i < (int)vdp.size() - 1; i++) {
		if (p == vdp[i].second) {
			return vdp[i + 1].second;
		}
	}
	return vdp[0].second;
}
//左手法でトレースして通った点の列を返す
points trace(const Lines &ls) {
	adjPoint aPoint;
	//隣接点(偏角付き)のリストを作成
	for (int i = 0; i < (int)ls.size(); i++) {
		aPoint[ls[i][0]].push_back(doublePoint(arg(ls[i][1] - ls[i][0]), ls[i][1]));
		aPoint[ls[i][1]].push_back(doublePoint(arg(ls[i][0] - ls[i][1]), ls[i][0]));
	}
	//x座標最小の点の計算と隣接点リストのソート
	point minPoint(INT_MAX, INT_MAX);
	adjPoint::iterator it;
	for (it = aPoint.begin(); it != aPoint.end(); ++it) {
		point p = it->first;
		minPoint = min(minPoint, p);
		vDoublePoint &vdp = it->second;
		sort(vdp.begin(), vdp.end());
	}
	points ret;
	ret.push_back(minPoint);
	//最初の移動先
	point curP = aPoint[minPoint][0].second;
	point lastP = minPoint;
	//トレースの繰り返し
	while (curP != minPoint) {
		if(DEBUG)cerr<<curP<<endl;
		ret.push_back(curP);
		point nextP = findNext(aPoint[curP], lastP);
		//if(isSamePoint(curP,nextP))break;
		lastP = curP;
		curP = nextP;
	}
	//開始点を最後にも追加
	ret.push_back(minPoint);
	return ret;
}

bool isInside(const points &ps) {
	Line l0(point(0, 0), point(51.0, 1.0 / 20000.0));
	int count = 0;
	for (int i = 0; i < (int)ps.size() - 1; i++) {
		point dummy;
		Line l1(ps[i], ps[i + 1]);
		if (intersect(l0, l1,dummy))count++;
	}
	return (count & 1) == 1;
}


//円
struct Circle {
	point p; double r;
	Circle(const point &p_, double r_) : p(p_), r(r_) { }
};

//凸包
vector<point> convex_hull(vector<point> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<point> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

//2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
	double d = dist(p1, p2);
	double x1 = p1.real(), x2 = p2.real();
	double y1 = p1.imag(), y2 = p2.imag();
	if (p1.imag() == p2.imag()) {
		double x = (x1 + x2) / 2.0;
		double dy = sqrt(R - d * d / 4);
		return { { x,y1 + dy },{ x,y1 - dy } };
	}
	else {
		double m = (x1 - x2) / (y2 - y1);
		double t = sqrt(R*R - d * d / 4);
		double dx = sqrt((t*t) / (m*m + 1));
		double dy = sqrt(t*t - dx * dx);
		double gx = (x1 + x2) / 2;
		double gy = (y1 + y2) / 2;
		if (m > EPS) {
			return { { gx + dx,gy + dy },{ gx - dx,gy - dy } };
		}
		else {
			return { { gx + dx,gy - dy },{ gx - dx,gy + dy } };
		}
	}
}
//長方形
struct Square {
	double lx, ly, rx, ry;
	Square(double lx_, double ly_, double rx_, double ry_) :lx(lx_), ly(ly_), rx(rx_), ry(ry_) {};
	bool include(point &p) {
		return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
	}
};

struct Polygon : public vector<point> {
	//0->OUT, 1->ON, 2->IN
	int contains(const point &p) {
		bool in = false;
		int N = this->size();
		for (int i = 0; i < N; i++) {
			point a = this->at(i) - p;
			point b = this->at((i + 1) % N) - p;
			if (imag(a) > imag(b)) {
				std::swap(a, b);
			}
			if (imag(a) <= 0 && 0 < imag(b))
				if (cross(a, b) < 0)in = !in;
			if (cross(a, b) == 0 && dot(a, b) <= 0)return 1;
		}
		return in ? 2 : 0;
	}
};
clock_t START,END;
bool trapAll() {
	int N; cin >> N;
	if (N == 0){
		END=clock();
		double t=(double)(END-START)/CLOCKS_PER_SEC;
		if(DEBUG)cerr<<"elapsed time"<<t<<"[sec]"<<endl;
		exit(0);
	}
	Lines ls;
	REP(i, N) {
		double x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		point p1(x1, y1);
		point p2(x2, y2);
		ls.push_back(Line(p1, p2));
	}
	splitSegments(ls);
	// for(auto l:ls){
	// 	cerr<<l[0]<<" "<<l[1]<<endl;
	// }
	//cerr << "splitted" << endl;
	vLines vls = connectedComponent(ls);
	for (auto lines : vls) {
		Polygon poly;
		points ps= trace(lines);
		for (auto p : ps) {
			poly.push_back(p);
		}
		if (poly.contains(point(0, 0)))return true;
	}
	return false;
}

void solve() {
	if (trapAll())cout << "yes" << endl;
	else cout << "no" << endl;
	if(DEBUG)cerr<<"+++++++++++++"<<endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	START = clock();
	while (true)
		solve();

}
accuracy: 1
time_ms: 5140
memory_kb: 6448
final_rank: 14

code_snippet: #pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#pragma GCC optimize("unroll-loops")
#include"bits/stdc++.h"

using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,m,n) for(int i=(m);i<(n);i++)

const bool DEBUG = false;

const double EPS = 1e-8;
typedef complex<double> point;
istream &operator>>(istream &is, point &p) {
  double a, b;
  is >> a >> b;
  p = point(a, b);
  return is;
}
point operator*(const point&p, const double &d) {
	return point(real(p)*d, imag(p)*d);
}
namespace std {
	bool operator < (const point& a, const point& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

//直線or線分
struct Line : public vector<point> {
	Line(const point &a, const point &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<Line>Lines;


double cross(const point& a, const point& b) {
  return real(a)*imag(b)-imag(a)*real(b);
}
double dot(const point& a, const point& b) {
  return real(a)*real(b)+imag(a)*imag(b);
}
int ccw(point a, point b, point c) {
	b =b-a; c =c - a;
	if (cross(b, c) > EPS)   return +1;       // counter clockwise
	if (cross(b, c) < -EPS)   return -1;       // clockwise
	if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
	return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS || //non-parallel
		abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS; //same line
}
bool intersectLS(const Line &l, const Line &s) {
	return cross(l[1] - l[0], s[0] - l[0])* // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
	if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS)return false;
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}

bool intersectSP(const Line &s, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}
bool connectSS(const Line &s, const Line &t) {
	if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))return true;
	else return false;
}
bool isSamePoint(const point &p1,const point &p2){
	return abs(p1-p2)<EPS;
}
bool connectSS_with_endpoint(const Line &s,const Line &t){
	REP(i,2)REP(j,2){
		//if(isSamePoint(s[i],t[j]))return true;
		if(s[i]==t[j])return true;
	}
	return false;
}
bool intersectSS(const Line &s, const Line &t) {
	return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
		ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}
bool intersectSS_strict(const Line &s, const Line &t) {
	//端点が線分上に乗っている場合はfalseにする
	if (connectSS(s, t))return false;
	return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
		ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}

bool isOn(const Line &l,const point &p){
	if(l[0]==p||l[1]==p)return false;
	point d=l[1]-l[0];
	point p0=(p-l[0])/d;
	return p0.imag()==0.0&&0.0<p0.real()&&p0.real()<1.0;
}
bool intersect(const Line &l0,const Line &l1, point &p){
	if(connectSS_with_endpoint(l0,l1)||isOn(l0,l1[0])||isOn(l0,l1[1])||isOn(l1,l0[0])||isOn(l1,l0[1]))return false;
	point d = l0[1]-l0[0];
	point p0=(l1[0]-l0[0])/d;
	point p1=(l1[1]-l0[0])/d;
	if(p0.imag()*p1.imag()>=0)return false;
	double t=p0.imag()/(p0.imag()-p1.imag());
	double s=p0.real()*(1-t)+p1.real()*t;
	if(s<=0.0||1.0<=s)return false;
	p=l0[0]+d*s;
	return true;
}

//距離,交点
//射影 直線lにpから下した垂線との交点

point projection(const Line &l, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1])*t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) {
	return p + (projection(l, p) - p) * 2;
}
double distancePP(const point& a, const point& b) {
	return sqrt(norm(a - b));
}
double distanceLP(const Line &l, const point &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const Line&l, const Line &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
	if (intersectLS(l, s))return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
	const point r = projection(s, p);
	if (intersectSP(s, r))return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	if (intersectSS(s, t))return 0;
	return min({ distanceSP(s,t[0]),distanceSP(s,t[1]),distanceSP(t,s[0]),distanceSP(t,s[1]) });
}
point crosspoint(const Line &l, const Line &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS&&abs(B) < EPS)return m[0];//same line
	if (abs(A) < EPS)assert(false); // Precondition not satisfied
	return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) {
	return abs(p1 - p2);
}

//線分同士の交点で分割して端点以外の共有点を持たないようにする
void splitSegments(Lines &ls) {
	//端点が線分上に乗っている場合の分割
	for (size_t i = 0; i < ls.size(); i++)for (size_t j = i + 1; j < ls.size(); j++) {
		for (int k = 0; k < 2; k++) {
			if(isOn(ls[i],ls[j][k])){
			//if (intersectSP_without_endpoint(ls[i], ls[j][k])) {
				ls.push_back(Line(ls[i][0], ls[j][k]));
				ls[i][0] = ls[j][k];
				break;
			}
			else if(isOn(ls[j],ls[i][k])){
			//else if (intersectSP_without_endpoint(ls[j], ls[i][k])) {
				ls.push_back(Line(ls[j][0], ls[i][k]));
				ls[j][0] = ls[i][k];
				break;
			}
		}
	}
	//cerr << "split-1" << endl;
	//線分が交差している場合の分割
	for (size_t i = 0; i < ls.size(); i++) {
		Line li = ls[i];
		for (size_t j = i + 1; j < ls.size(); j++) {
			point cross_p;
			if(intersect(ls[i],ls[j],cross_p)){
			//if (intersectSS_strict(ls[i], ls[j])) {
				//point cross_p = crosspoint(ls[i], ls[j]);
				ls.push_back(Line(ls[i][0], cross_p));
				ls[i][0] = cross_p;
				ls.push_back(Line(ls[j][0], cross_p));
				ls[j][0] = cross_p;
			}
		}
	}
}

//線分の集合(split済み)を連結成分に分解する(union-find)

struct Equiv {
	vector<int>links;
	//大きさ1の同値類をn個作る
	Equiv(int n):links(n){
		for (int i = 0; i < n; i++) {
			links[i] = i;
		}
	}
	//xの属する同値類の代表元を返す
	int find(int x) {
		int xx = links[x];
		if (xx == x)return x;
		return links[x] = find(xx);
	}
	void unify(int x, int y) {
		int xx = find(x), yy = find(y);
		if (xx <= yy)links[yy] = xx;
		else links[xx] = yy;
	}
};

typedef vector<Lines>vLines;
vLines connectedComponent(const Lines &ls) {
	vLines ret;
	Equiv equiv(ls.size());
	for (int i = 0; i < (int)ls.size(); i++) {
		for (int j = 0; j < i; j++) {
			if (connectSS_with_endpoint(ls[i], ls[j])) {
				equiv.unify(i, j);
			}
		}
	}
	//cerr << "connected-1" << endl;
	for (int i = 0; i < (int)ls.size(); i++) {
		if (equiv.find(i) == i) {
			Lines newLs;
			newLs.push_back(ls[i]);
			for (int j = i + 1; j < (int)ls.size(); j++) {
				if (equiv.find(j) == i)newLs.push_back(ls[j]);
			}
			ret.push_back(newLs);
		}
	}
	return ret;
}
//左手法でのトレース
//偏角でソートされた隣接点のvectorを得る
typedef pair<double, point>doublePoint;
typedef vector<doublePoint> vDoublePoint;
typedef map<point, vDoublePoint> adjPoint;
typedef vector<point>points;
//移動前の点と隣接点のリストから移動先を決定
point findNext(const vDoublePoint &vdp, const point &p) {
	for (int i = 0; i < (int)vdp.size() - 1; i++) {
		if (p == vdp[i].second) {
			return vdp[i + 1].second;
		}
	}
	return vdp[0].second;
}
//左手法でトレースして通った点の列を返す
points trace(const Lines &ls) {
	adjPoint aPoint;
	//隣接点(偏角付き)のリストを作成
	for (int i = 0; i < (int)ls.size(); i++) {
		aPoint[ls[i][0]].push_back(doublePoint(arg(ls[i][1] - ls[i][0]), ls[i][1]));
		aPoint[ls[i][1]].push_back(doublePoint(arg(ls[i][0] - ls[i][1]), ls[i][0]));
	}
	//x座標最小の点の計算と隣接点リストのソート
	point minPoint(INT_MAX, INT_MAX);
	adjPoint::iterator it;
	for (it = aPoint.begin(); it != aPoint.end(); ++it) {
		point p = it->first;
		minPoint = min(minPoint, p);
		vDoublePoint &vdp = it->second;
		sort(vdp.begin(), vdp.end());
	}
	points ret;
	ret.push_back(minPoint);
	//最初の移動先
	point curP = aPoint[minPoint][0].second;
	point lastP = minPoint;
	//トレースの繰り返し
	while (curP != minPoint) {
		if(DEBUG)cerr<<curP<<endl;
		ret.push_back(curP);
		point nextP = findNext(aPoint[curP], lastP);
		//if(isSamePoint(curP,nextP))break;
		lastP = curP;
		curP = nextP;
	}
	//開始点を最後にも追加
	ret.push_back(minPoint);
	return ret;
}

bool isInside(const points &ps) {
	Line l0(point(0, 0), point(51.0, 1.0 / 20000.0));
	int count = 0;
	for (int i = 0; i < (int)ps.size() - 1; i++) {
		point dummy;
		Line l1(ps[i], ps[i + 1]);
		if (intersect(l0, l1,dummy))count++;
	}
	return (count & 1) == 1;
}


//円
struct Circle {
	point p; double r;
	Circle(const point &p_, double r_) : p(p_), r(r_) { }
};

//凸包
vector<point> convex_hull(vector<point> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<point> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

//2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
	double d = dist(p1, p2);
	double x1 = p1.real(), x2 = p2.real();
	double y1 = p1.imag(), y2 = p2.imag();
	if (p1.imag() == p2.imag()) {
		double x = (x1 + x2) / 2.0;
		double dy = sqrt(R - d * d / 4);
		return { { x,y1 + dy },{ x,y1 - dy } };
	}
	else {
		double m = (x1 - x2) / (y2 - y1);
		double t = sqrt(R*R - d * d / 4);
		double dx = sqrt((t*t) / (m*m + 1));
		double dy = sqrt(t*t - dx * dx);
		double gx = (x1 + x2) / 2;
		double gy = (y1 + y2) / 2;
		if (m > EPS) {
			return { { gx + dx,gy + dy },{ gx - dx,gy - dy } };
		}
		else {
			return { { gx + dx,gy - dy },{ gx - dx,gy + dy } };
		}
	}
}
//長方形
struct Square {
	double lx, ly, rx, ry;
	Square(double lx_, double ly_, double rx_, double ry_) :lx(lx_), ly(ly_), rx(rx_), ry(ry_) {};
	bool include(point &p) {
		return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
	}
};

struct Polygon : public vector<point> {
	//0->OUT, 1->ON, 2->IN
	int contains(const point &p) {
		bool in = false;
		int N = this->size();
		for (int i = 0; i < N; i++) {
			point a = this->at(i) - p;
			point b = this->at((i + 1) % N) - p;
			if (imag(a) > imag(b)) {
				std::swap(a, b);
			}
			if (imag(a) <= 0 && 0 < imag(b))
				if (cross(a, b) < 0)in = !in;
			if (cross(a, b) == 0 && dot(a, b) <= 0)return 1;
		}
		return in ? 2 : 0;
	}
};
clock_t START,END;
bool trapAll() {
	int N; cin >> N;
	if (N == 0){
		END=clock();
		double t=(double)(END-START)/CLOCKS_PER_SEC;
		//cerr<<"elapsed time"<<t<<"[sec]"<<endl;
		exit(0);
	}
	Lines ls;
	REP(i, N) {
		double x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		point p1(x1, y1);
		point p2(x2, y2);
		ls.push_back(Line(p1, p2));
	}
	splitSegments(ls);
	// for(auto l:ls){
	// 	cerr<<l[0]<<" "<<l[1]<<endl;
	// }
	//cerr << "splitted" << endl;
	vLines vls = connectedComponent(ls);
	for (auto lines : vls) {
		Polygon poly;
		points ps= trace(lines);
		for (auto p : ps) {
			poly.push_back(p);
		}
		if (poly.contains(point(0, 0)))return true;
	}
	return false;
}

void solve() {
	if (trapAll())cout << "yes" << endl;
	else cout << "no" << endl;
	if(DEBUG)cerr<<"+++++++++++++"<<endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	START = clock();
	while (true)
		solve();

}
accuracy: 1
time_ms: 5150
memory_kb: 6436
final_rank: 15

code_snippet: #include"bits/stdc++.h"

using namespace std;

#define REP(i,n) for(int i=0;i<(n);i++)
#define FOR(i,m,n) for(int i=(m);i<(n);i++)

const double EPS = 1e-8;
typedef complex<double> point;
point operator*(const point&p, const double &d) {
	return point(real(p)*d, imag(p)*d);
}
namespace std {
	bool operator < (const point& a, const point& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}

	//istream &operator>>(istream &stream, point &p) {
	//	stream >> p.real >> p.imag;
	//	return stream;
	//}
}
//bool intersectLL(const Line &l1, const Line &l2);
//bool intersectLS(const Line &l, const Line &s);
//bool intersectLP(const Line &l, const point &p);
//bool intersectSS(const Line &s, const Line &t);
//bool intersectSP(const Line &s, const point &p);

//直線or線分
struct Line : public vector<point> {
	Line(const point &a, const point &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<Line>Lines;


//外積
double cross(const point& a, const point& b) {
	return imag(conj(a)*b);
}
//内積
double dot(const point& a, const point& b) {
	return real(conj(a)*b);
}
int ccw(point a, point b, point c) {
	b -= a; c -= a;
	if (cross(b, c) > 0)   return +1;       // counter clockwise
	if (cross(b, c) < 0)   return -1;       // clockwise
	if (dot(b, c) < 0)     return +2;       // c--a--b on line
	if (norm(b) < norm(c)) return -2;       // a--b--c on line
	return 0;
}
//交差判定
bool intersectLL(const Line &l1, const Line &l2) {
	return abs(cross(l1[1] - l1[0], l2[1] - l2[0])) > EPS || //non-parallel
		abs(cross(l1[1] - l1[0], l2[0] - l1[0])) < EPS; //same line
}
bool intersectLS(const Line &l, const Line &s) {
	return cross(l[1] - l[0], s[0] - l[0])* // s[0] is left of l
		cross(l[1] - l[0], s[1] - l[0]) < EPS; // s[1] is right of l
}
bool intersectLP(const Line &l, const point &p) {
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
//端点に乗ってたらfalse
bool intersectSP_without_endpoint(const Line &s, const point &p) {
	if (abs(s[0] - p) < EPS || abs(s[1] - p) < EPS)return false;
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}

bool intersectSP(const Line &s, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; //triangle inequality
}
bool connectSS(const Line &s, const Line &t) {
	if (intersectSP(s, t[0]) || intersectSP(s, t[1]) || intersectSP(t, s[0]) || intersectSP(t, s[1]))return true;
	else return false;
}
bool isSamePoint(const point &p1,const point &p2){
	return abs(p1-p2)<EPS;
}
bool connectSS_with_endpoint(const Line &s,const Line &t){
	REP(i,2)REP(j,2){
		//if(isSamePoint(s[i],t[j]))return true;
		if(s[i]==t[j])return true;
	}
	return false;
}
bool intersectSS(const Line &s, const Line &t) {
	//端点が線分上に乗っている場合はfalseにする
	if (connectSS(s, t))return false;
	return ccw(s[0], s[1], t[0])*ccw(s[0], s[1], t[1]) <= 0 &&
		ccw(t[0], t[1], s[0])*ccw(t[0], t[1], s[1]) <= 0;
}

bool isOn(const Line &l,const point &p){
	if(l[0]==p||l[1]==p)return false;
	point d=l[1]-l[0];
	point p0=(p-l[0])/d;
	return p0.imag()==0.0&&0.0<p0.real()&&p0.real()<1.0;
}
bool intersect(const Line &l0,const Line &l1, point &p){
	if(connectSS_with_endpoint(l0,l1)||isOn(l0,l1[0])||isOn(l0,l1[1])||isOn(l1,l0[0])||isOn(l1,l0[1]))return false;
	point d = l0[1]-l0[0];
	point p0=(l1[0]-l0[0])/d;
	point p1=(l1[1]-l0[0])/d;
	if(p0.imag()*p1.imag()>=0)return false;
	double t=p0.imag()/(p0.imag()-p1.imag());
	double s=p0.real()*(1-t)+p1.real()*t;
	if(s<=0.0||1.0<=s)return false;
	p=l0[0]+d*s;
	return true;
}

//距離,交点
//射影 直線lにpから下した垂線との交点

point projection(const Line &l, const point &p) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	double t = dot(p - l[0], l[0] - l[1]) / norm(l[0] - l[1]);
	return l[0] + (l[0] - l[1])*t;
}
//射影 直線lを対象軸としてpと線対称にある点
point reflection(const Line &l, const point &p) {
	return p + (projection(l, p) - p) * 2;
}
double distancePP(const point& a, const point& b) {
	return sqrt(norm(a - b));
}
double distanceLP(const Line &l, const point &p) {
	return abs(p - projection(l, p));
}
double distanceLL(const Line&l, const Line &m) {
	return intersectLL(l, m) ? 0 : distanceLP(l, m[0]);
}
double distanceLS(const Line &l, const Line &s) {
	if (intersectLS(l, s))return 0;
	return min(distanceLP(l, s[0]), distanceLP(l, s[1]));
}
double distanceSP(const Line &s, const point &p) {
	const point r = projection(s, p);
	if (intersectSP(s, r))return abs(r - p);
	return min(abs(s[0] - p), abs(s[1] - p));
}
double distanceSS(const Line &s, const Line &t) { //verified on 2020/04/03 https://onlinejudge.u-aizu.ac.jp/status/users/Mojumbo/submissions/1/1157/judge/4316978/C++14
	if (intersectSS(s, t))return 0;
	return min({ distanceSP(s,t[0]),distanceSP(s,t[1]),distanceSP(t,s[0]),distanceSP(t,s[1]) });
}
point crosspoint(const Line &l, const Line &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS&&abs(B) < EPS)return m[0];//same line
	if (abs(A) < EPS)assert(false); // Precondition not satisfied
	return m[0] + B / A * (m[1] - m[0]);
}
double dist(point &p1, point &p2) {
	return abs(p1 - p2);
}

//線分同士の交点で分割して端点以外の共有点を持たないようにする
void splitSegments(Lines &ls) {
	//端点が線分上に乗っている場合の分割
	for (size_t i = 0; i < ls.size(); i++)for (size_t j = i + 1; j < ls.size(); j++) {
		for (int k = 0; k < 2; k++) {
			if(isOn(ls[i],ls[j][k])){
			//if (intersectSP_without_endpoint(ls[i], ls[j][k])) {
				ls.push_back(Line(ls[i][0], ls[j][k]));
				ls[i][0] = ls[j][k];
				break;
			}
			else if(isOn(ls[j],ls[i][k])){
			//else if (intersectSP_without_endpoint(ls[j], ls[i][k])) {
				ls.push_back(Line(ls[j][0], ls[i][k]));
				ls[j][0] = ls[i][k];
				break;
			}
		}
	}
	//cerr << "split-1" << endl;
	//線分が交差している場合の分割
	for (size_t i = 0; i < ls.size(); i++) {
		Line li = ls[i];
		for (size_t j = i + 1; j < ls.size(); j++) {
			point cross_p;
			if(intersect(ls[i],ls[j],cross_p)){
			//if (intersectSS(ls[i], ls[j])) {
				//point cross_p = crosspoint(ls[i], ls[j]);
				ls.push_back(Line(ls[i][0], cross_p));
				ls[i][0] = cross_p;
				ls.push_back(Line(ls[j][0], cross_p));
				ls[j][0] = cross_p;
			}
		}
	}
}

//線分の集合(split済み)を連結成分に分解する(union-find)
struct Equiv {
	vector<int>links;
	//大きさ1の同値類をn個作る
	Equiv(int n) :links(n) {
		for (int i = 0; i < n; i++) {
			links[i] = i;
		}
	}
	//xの属する同値類の代表元を返す
	int find(int x) {
		int xx = links[x];
		if (xx == x)return x;
		return links[x] = find(xx);
	}
	void unify(int x, int y) {
		int xx = find(x), yy = find(y);
		if (xx <= yy)links[yy] = xx;
		else links[xx] = yy;
	}
};

typedef vector<Lines>vLines;
vLines connectedComponent(const Lines &ls) {
	vLines ret;
	Equiv equiv(ls.size());
	for (int i = 0; i < (int)ls.size(); i++) {
		for (int j = 0; j < i; j++) {
			if (connectSS_with_endpoint(ls[i], ls[j])) {
				equiv.unify(i, j);
			}
		}
	}
	//cerr << "connected-1" << endl;
	for (int i = 0; i < (int)ls.size(); i++) {
		if (equiv.find(i) == i) {
			Lines newLs;
			newLs.push_back(ls[i]);
			for (int j = i + 1; j < (int)ls.size(); j++) {
				if (equiv.find(j) == i)newLs.push_back(ls[j]);
			}
			ret.push_back(newLs);
		}
	}
	return ret;
}
//左手法でのトレース
//偏角でソートされた隣接点のvectorを得る
typedef pair<double, point>doublePoint;
typedef vector<doublePoint> vDoublePoint;
typedef map<point, vDoublePoint> adjPoint;
typedef vector<point>points;
//移動前の点と隣接点のリストから移動先を決定
point findNext(const vDoublePoint &vdp, const point &p) {
	for (int i = 0; i < (int)vdp.size() - 1; i++) {
		if (p == vdp[i].second) {
			return vdp[i + 1].second;
		}
	}
	return vdp[0].second;
}
//左手法でトレースして通った点の列を返す
points trace(const Lines &ls) {
	adjPoint aPoint;
	//隣接点(偏角付き)のリストを作成
	for (int i = 0; i < (int)ls.size(); i++) {
		aPoint[ls[i][0]].push_back(doublePoint(arg(ls[i][1] - ls[i][0]), ls[i][1]));
		aPoint[ls[i][1]].push_back(doublePoint(arg(ls[i][0] - ls[i][1]), ls[i][0]));
	}
	//x座標最小の点の計算と隣接点リストのソート
	point minPoint(INT_MAX, INT_MAX);
	adjPoint::iterator it;
	for (it = aPoint.begin(); it != aPoint.end(); ++it) {
		point p = it->first;
		minPoint = min(minPoint, p);
		vDoublePoint &vdp = it->second;
		sort(vdp.begin(), vdp.end());
	}
	points ret;
	ret.push_back(minPoint);
	//最初の移動先
	point curP = aPoint[minPoint][0].second;
	point lastP = minPoint;
	//トレースの繰り返し
	int cnt =0;
	while (curP != minPoint) {
		//cerr<<curP<<endl;
		cnt++;
		assert(cnt<1000000);
		ret.push_back(curP);
		point nextP = findNext(aPoint[curP], lastP);
		//if(isSamePoint(curP,nextP))break;
		lastP = curP;
		curP = nextP;
	}
	//開始点を最後にも追加
	ret.push_back(minPoint);
	return ret;
}

bool isInside(const points &ps) {
	Line l0(point(0, 0), point(51.0, 1.0 / 20000.0));
	int count = 0;
	for (int i = 0; i < (int)ps.size() - 1; i++) {
		point dummy;
		Line l1(ps[i], ps[i + 1]);
		if (intersect(l0, l1,dummy))count++;
	}
	return (count & 1) == 1;
}


//円
struct Circle {
	point p; double r;
	Circle(const point &p_, double r_) : p(p_), r(r_) { }
};

//凸包
vector<point> convex_hull(vector<point> ps) {
	int n = ps.size(), k = 0;
	sort(ps.begin(), ps.end());
	vector<point> ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++]) // lower-hull
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--]) // upper-hull
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}

//2点を通る半径Rの円の中心
pair<point, point> get_circle_from_2points(point &p1, point &p2, double R) {
	double d = dist(p1, p2);
	double x1 = p1.real(), x2 = p2.real();
	double y1 = p1.imag(), y2 = p2.imag();
	if (p1.imag() == p2.imag()) {
		double x = (x1 + x2) / 2.0;
		double dy = sqrt(R - d * d / 4);
		return { { x,y1 + dy },{ x,y1 - dy } };
	}
	else {
		double m = (x1 - x2) / (y2 - y1);
		double t = sqrt(R*R - d * d / 4);
		double dx = sqrt((t*t) / (m*m + 1));
		double dy = sqrt(t*t - dx * dx);
		double gx = (x1 + x2) / 2;
		double gy = (y1 + y2) / 2;
		if (m > EPS) {
			return { { gx + dx,gy + dy },{ gx - dx,gy - dy } };
		}
		else {
			return { { gx + dx,gy - dy },{ gx - dx,gy + dy } };
		}
	}
}
//長方形
struct Square {
	double lx, ly, rx, ry;
	Square(double lx_, double ly_, double rx_, double ry_) :lx(lx_), ly(ly_), rx(rx_), ry(ry_) {};
	bool include(point &p) {
		return p.real() + EPS >= lx && p.real() - EPS <= rx && p.imag() + EPS >= ly && p.imag() - EPS <= ry;
	}
};

struct Polygon : public vector<point> {
	//0->OUT, 1->ON, 2->IN
	int contains(const point &p) {
		bool in = false;
		int N = this->size();
		for (int i = 0; i < N; i++) {
			point a = this->at(i) - p;
			point b = this->at((i + 1) % N) - p;
			if (imag(a) > imag(b)) {
				std::swap(a, b);
			}
			if (imag(a) <= 0 && 0 < imag(b))
				if (cross(a, b) < 0)in = !in;
			if (cross(a, b) == 0 && dot(a, b) <= 0)return 1;
		}
		return in ? 2 : 0;
	}
};

bool trapAll() {
	int N; cin >> N;
	if (N == 0)exit(0);
	Lines ls;
	REP(i, N) {
		double x1, y1, x2, y2;
		cin >> x1 >> y1 >> x2 >> y2;
		point p1(x1, y1);
		point p2(x2, y2);
		ls.push_back(Line(p1, p2));
	}
	splitSegments(ls);
	// for(auto l:ls){
	// 	cerr<<l[0]<<" "<<l[1]<<endl;
	// }
	//cerr << "splitted" << endl;
	vLines vls = connectedComponent(ls);
	for (auto lines : vls) {
		Polygon poly;
		points ps= trace(lines);
		for (auto p : ps) {
			poly.push_back(p);
		}
		if (poly.contains(point(0, 0)))return true;
	}
	return false;
}
void solve() {
	if (trapAll())cout << "yes" << endl;
	else cout << "no" << endl;
	//cerr<<"+++++++++++++"<<endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	while (true)
		solve();
}
accuracy: 1
time_ms: 5390
memory_kb: 6372
final_rank: 16

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <vector>
#include <utility>
#include <set>
//#define LOCAL
#define maxv 205
#define maxn 105
#define EPS 1e-10
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
struct Point{
	double x,y;
	Point(double x = 0.0,double y = 0.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 lambda){
		return Point(x * lambda,y * lambda);
	}
	Point operator / (double lambda){
		return Point(x / lambda,y / lambda);
	}
	double norm(){
		return x * x + y * y;
	}
	double abs_(){
		return sqrt(norm());
	}
	double pol(){
		return atan2(y,x);
	}
	bool operator == (const Point &p)const
	{
		return abs(x - p.x) < EPS && abs(y - p.y) < EPS;
	}
	bool operator < (const Point &p)const
	{
		if(abs(x - p.x) < EPS) return y < p.y;
		else return x < p.x;
	}
};
typedef Point Vector;
struct Segment{
	Point p1,p2;
	Segment(Point p1 = Point(),Point p2 = Point()): p1(p1),p2(p2) {}
};
Point front(Segment s){
	Vector a = s.p2 - s.p1;
	a = a / a.abs_() * 5e-4;
	return s.p2 + a;
}
Point back(Segment s){
	Vector a = s.p2 - s.p1;
	a = a / a.abs_() * 5e-4;
	return s.p1 - a;
}
typedef Segment Line;
typedef vector<Point> Polygon;
double dot(Vector a,Vector b){ return a.x * b.x + a.y * b.y; }
double det(Vector a,Vector b){ return a.x * b.y - a.y * b.x; }
vector <int> adj[maxv];
Point p[maxv]; int pk;
Segment s[maxn]; int n;
int ccw(Point p,Segment l){
	if(det(l.p2 - l.p1,p - l.p1) > EPS) return 1;
	if(det(l.p2 - l.p1,p - l.p1) < -EPS) return -1;
	if(dot(l.p2 - l.p1,p - l.p1) < -EPS) return 2;
	if((l.p2 - l.p1).norm() < (p - l.p1).norm()) return -2;
	return 0;
}
bool cross(Segment s1,Segment s2){
	return ccw(s1.p1,s2) * ccw(s1.p2,s2) <= 0 && ccw(s2.p1,s1) * ccw(s2.p2,s1) <= 0;
}
bool check(Point p1,Point p2){
	for(int i=1;i<=n;i++){
		if(cross(Segment(p1,p2),s[i])) return false;
	}
	return true;
}
bool vis[maxv];
void dfs(int u){
	vis[u] = true;
	for(int i=0;i<(int)adj[u].size();i++){
		int v = adj[u][i];
		if(!vis[v]) dfs(v);
	}
}
int main(){
	#ifdef LOCAL
	freopen("sample.in","r",stdin);
	freopen("sample.out","w",stdout);
	#endif
	while(~scanf("%d",&n) && n){
		for(int i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&s[i].p1.x,&s[i].p1.y,&s[i].p2.x,&s[i].p2.y);
		pk = 0;
		p[++pk] = Point(0,0);
		p[++pk] = Point(100,100);
		for(int i=1;i<=n;i++){
			p[++pk] = front(s[i]);
			p[++pk] = back(s[i]);
		}
		for(int i=1;i<=pk;i++) adj[i].clear();
		for(int i=1;i<=pk;i++){
			for(int j=i+1;j<=pk;j++){
				if(check(p[i],p[j])){
					adj[i].push_back(j);
					adj[j].push_back(i);
				}
			}
		}
		memset(vis,0,sizeof(vis));
		dfs(1);
		if(vis[2]) puts("no");
		else puts("yes");
	}
	return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3388
final_rank: 2

code_snippet: #include <iostream>
#include <complex>
#include <vector>
#include <utility>
#include <algorithm>
using namespace std;
using P = complex<double>;
using L = pair<P,P>;
#define X real()
#define Y imag()
const double EPS = 1e-6, INF = 1e12;

double dot(P &a, P &b){ return a.X*b.X + a.Y*b.Y;}
double cross(P &a, P &b){ return a.X*b.Y - a.Y*b.X;}

int ccw(P a, P b, P c){
  b -= a, c -= a;
  if(cross(b,c) > EPS) return 1;
  if(cross(b,c) < -EPS) return -1;
  if(dot(b,c) < EPS) return 2;
  if(norm(b) - EPS < norm(c)) return -2;
  return 0;
}

bool is_cross(L a, L b){
  P af = a.first, as = a.second, bf = b.first, bs = b.second;
  return (ccw(af,as,bs)*ccw(af,as,bf) <= 0) and (ccw(bf,bs,af)*ccw(bf,bs,as) <= 0);
}

int main(){
  int n;
  while(cin >> n, n){
    vector<L> Lines;
    for(int i = 0; i < n; ++i){
      double x, y, z, w;
      cin >> x >> y >> z >> w;
      x *= 200;
      y *= 200;
      z *= 200;
      w *= 200;
      Lines.emplace_back(P(x,y),P(z,w));
    }
    for(int i = 0; i < n; ++i){
      P d = Lines[i].second - Lines[i].first;
      d /= abs(d);
      Lines[i].second += d;
      Lines[i].first -= d;
    }
    vector< vector<int> > Adj(2*n+2, vector<int>(2*n+2,true));
    int M = 2*n + 2;
    vector<P> Points(M);
    for(int i = 0; i < n; ++i){
      Points[2*i] = Lines[i].first;
      Points[2*i+1] = Lines[i].second;
    }
    Points[2*n] = P(0,0);
    Points[2*n+1] = P(200000,200000);
    for(int i = 0; i < M; ++i){
      for(int j = 0; j < i; ++j){
        if(i == j) continue;
        if(i < 2*n and i%2 == 0 and (j-i) == 1) continue;
        for(int k = 0; k < n; ++k){
          if(is_cross(L(Points[i],Points[j]),Lines[k])){
            Adj[i][j] = false;
            Adj[j][i] = false;
            break;
          }
        }
      }
    }
    for(int k = 0; k < M; ++k){
      for(int i = 0; i < M; ++i)
        for(int j = 0; j < M; ++j)
          Adj[i][j] |= Adj[i][k]&Adj[k][j];
    }
    if(Adj[M-1][M-2]) cout << "no" << endl;
    else cout << "yes" << endl;
  }
}
accuracy: 1
time_ms: 60
memory_kb: 3332
final_rank: 1

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
#include <map>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
struct L : array<P, 2>{
    L(const P& a, const P& b){ at(0)=a; at(1)=b; }
    L(){}
};

namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}
P unit(const P &p){
    return p/abs(p);
}
P rotate(const P &p, double rad){
    return p *P(cos(rad), sin(rad));
}

bool intersectSS(const L& a, const L& b){
    return ( ccw(a[0],a[1],b[0]) *ccw(a[0],a[1],b[1]) <= 0 ) &&
        ( ccw(b[0],b[1],a[0]) *ccw(b[0],b[1],a[1]) <= 0 );
}
bool intersectSP(const L& s, const P &p){
    return abs(cross(s[0]-p, s[1]-p))<EPS  && dot(s[0]-p, s[1]-p)<EPS;
}

bool isParallel(const P &a, const P &b){
    return abs(cross(a,b)) < EPS;
}
bool isParallel(const L &a, const L &b){
    return isParallel(a[1]-a[0], b[1]-b[0]);
}

P crosspointLL(const L &l, const L &m) {
  double A = cross(l[1]-l[0], m[1]-m[0]);
  double B = cross(l[1]-l[0], l[1]-m[0]);
  return m[0] + B/A *(m[1]-m[0]);
}

double getarea(const VP &poly){
    double ret = 0;
    for (int i=0; i<(int)poly.size(); i++){ 
        ret += cross(poly[i], poly[(i+1)%poly.size()]);
    }
    return ret*0.5;
}

int in_poly(const P &p, const VP &poly){
    int n = poly.size();
    int ret = -1;
    for(int i=0; i<n; i++){
        P a = poly[i]-p;
        P b = poly[(i+1)%n]-p;
        if(a.Y > b.Y) swap(a,b);
        if(intersectSP(L(a,b), P(0,0))) return 0;
        if(a.Y<=0 && b.Y>0 && cross(a,b)<0) ret = -ret;
    }
    return ret;
}

int leftmostpoint(int &pidx, int &cidx, vector<int> &vec, VP &plist){
    P ptoc = plist[cidx] -plist[pidx];
    int nextidx = -1;
    double maxangle = -INF;
    for(int i=0; i<(int)vec.size(); i++){
        P cton = plist[vec[i]] -plist[cidx];
        double angle;
        if(abs(cross(ptoc, cton)) < EPS && dot(ptoc, cton) <EPS){
            angle = -PI;
        }else{
            angle = arg(cton/ ptoc);
        }
        if(angle > maxangle){
            maxangle = angle;
            nextidx = i;
        }
    }
    pidx = cidx;
    cidx = vec[nextidx];
    return nextidx;
}

vector<vector<int> > makeDualGraph(vector<vector<int> > &adj, VP &plist, vector<VP> &vlist){
    map<pair<int,int>, int> edgelist;
    vector<vector<int> > poly;
    vector<vector<bool> > used(adj.size());
    for(int i=0; i<(int)adj.size(); i++){
        used[i] = vector<bool>(adj[i].size(), false);
    }
    vlist = vector<VP>();
      
    int numarea=0;
    for(int i=0; i<(int)adj.size(); i++){
        for(int j=0; j<(int)adj[i].size(); j++){
            if(used[i][j]) continue;
            used[i][j] = true;
            vlist.push_back(VP());
            vector<int> border;
            border.push_back(i);
            vlist[numarea].push_back(plist[i]);
            int prev = i;
            int curr = adj[i][j];
            while(curr!=i){
                border.push_back(curr);
                vlist[numarea].push_back(plist[curr]);
                int idx = leftmostpoint(prev, curr, adj[curr], plist);
                used[prev][idx] = true;
            }
            poly.push_back(border);
            numarea++;
        }
    }
      
    vector<vector<int> > dual(numarea);
    for(int i=0; i<numarea; i++){
        for(int j=0; j<(int)poly[i].size(); j++){
            int a = poly[i][j];
            int b = poly[i][(j+1)%(int)poly[i].size()];
            pair<int,int> key = make_pair(min(a,b), max(a,b));
            if(edgelist.count(key) == 0){
                edgelist[key] = i;
            }else{
                dual[i].push_back(edgelist[key]);
                dual[edgelist[key]].push_back(i);
            }
        }
    }
      
    for(int i=0; i<(int)dual.size(); i++){
        sort(dual[i].begin(), dual[i].end());
        dual[i].erase(unique(dual[i].begin(), dual[i].end()), dual[i].end());
    }
    return dual;
}

pair<vector<vector<int> >, VP> arrangement(const vector<L> &l){
    vector<VP> cp(l.size());
    VP plist;
    for(int i=0; i<(int)l.size(); i++){
        for(int j=i+1; j<(int)l.size(); j++){
            if(!isParallel(l[i], l[j]) && intersectSS(l[i], l[j])){
                P cpij = crosspointLL(l[i], l[j]);
                cp[i].push_back(cpij);
                cp[j].push_back(cpij);
                plist.push_back(cpij);
            }
        }
        cp[i].push_back(l[i][0]);
        cp[i].push_back(l[i][1]);
        plist.push_back(l[i][0]);
        plist.push_back(l[i][1]);
        sort(cp[i].begin(), cp[i].end());
        cp[i].erase(unique(cp[i].begin(), cp[i].end()), cp[i].end());
    }
    sort(plist.begin(), plist.end());
    plist.erase(unique(plist.begin(), plist.end()), plist.end());

    int n = plist.size();
    map<P, int> conv;
    for(int i=0; i<n; i++){
        conv[plist[i]] = i;
    }
    vector<vector<int> > adj(n);
    for(int i=0; i<(int)cp.size(); i++){
        for(int j=0; j<(int)cp[i].size()-1; j++){
            int jidx = conv[cp[i][j]];
            int jp1idx = conv[cp[i][j+1]];
            adj[jidx].push_back(jp1idx);
            adj[jp1idx].push_back(jidx);
        }
    }
    for(int i=0; i<n; i++){
        sort(adj[i].begin(), adj[i].end());
        adj[i].erase(unique(adj[i].begin(), adj[i].end()), adj[i].end());
    }
    return make_pair(adj, plist);
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n == 0) break;

        vector<L> l(n);
        for(int i=0; i<n; i++){
            double xs,ys,xt,yt;
            cin >> xs >> ys >> xt >> yt;
            l[i] = L(P(xs, ys), P(xt, yt));
        }

        auto ret = arrangement(l);
        auto &adj = ret.first;
        VP &plist = ret.second;
        vector<VP> vlist;
        makeDualGraph(adj, plist, vlist);
        bool ok = false;
        for(const VP &poly: vlist){
            if(getarea(poly) < EPS) continue;
            if(in_poly(P(0, 0), poly) == 1){
                ok = true;
                break;
            }
        }
        if(ok){
            cout << "yes" << endl;
        }else{
            cout << "no" << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 5872
final_rank: 3