Problem:
Problem E:
Origami Through-Hole
Origami is the traditional Japanese art of paper folding. One day, Professor Egami found the
message board decorated with some pieces of origami works pinned on it, and became interested
in the pinholes on the origami paper. Your mission is to simulate paper folding and pin punching
on the folded sheet, and calculate the number of pinholes on the original sheet when unfolded.
A sequence of folding instructions for a flat and square piece of paper and a single pinhole
position are specified. As a folding instruction, two points
P
and
Q
are given. The paper should
be folded so that
P
touches
Q
from above (Figure 4). To make a fold, we first divide the sheet
into two segments by creasing the sheet along the
folding line
, i.e., the perpendicular bisector
of the line segment
PQ
, and then turn over the segment containing
P
onto the other. You can
ignore the thickness of the paper.
Figure 4: Simple case of paper folding
The original flat square piece of paper is folded into a structure consisting of layered paper
segments, which are connected by linear hinges. For each instruction, we fold one or more paper
segments along the specified folding line, dividing the original segments into new smaller ones.
The folding operation turns over some of the paper segments (not only the new smaller segments
but also some other segments that have no intersection with the folding line) to the reflective
position against the folding line. That is, for a paper segment that intersects with the folding
line, one of the two new segments made by dividing the original is turned over; for a paper
segment that does not intersect with the folding line, the whole segment is simply turned over.
The folding operation is carried out repeatedly applying the following rules, until we have no
segment to turn over.
Rule 1: The uppermost segment that contains
P
must be turned over.
Rule 2: If a hinge of a segment is moved to the other side of the folding line by the
  operation, any segment that shares the same hinge must be turned over.
Rule 3: If two paper segments overlap and the lower segment is turned over, the upper
segment must be turned over too.
In the examples shown in Figure 5, (a) and (c) show cases where only Rule 1 is applied. (b)
shows a case where Rule 1 and 2 are applied to turn over two paper segments connected by a
hinge, and (d) shows a case where Rule 1, 3 and 2 are applied to turn over three paper segments.
Figure 5: Different cases of folding
After processing all the folding instructions, the pinhole goes through all the layered segments
of paper at that position. In the case of Figure 6, there are three pinholes on the unfolded sheet
of paper.
Figure 6: Number of pinholes on the unfolded sheet
Input
The input is a sequence of datasets. The end of the input is indicated by a line containing a
zero.
Each dataset is formatted as follows.
k
p
x
1
p
y
1
q
x
1
q
y
1
.
.
.
p
x
k
p
y
k
q
x
k
q
y
k
h
x
h
y
For all datasets, the size of t
...(truncated)

Submitted solutions:

code_snippet: #include <iostream>
#include <cstdio>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <array>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
#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(){}
};

struct poly_connect{
    VP v;
    vector<int> c;
};

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
}

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;
}
P projection(const L& l, const P& p) {
  double t = dot(p-l[0], l[0]-l[1]) / norm(l[0]-l[1]);
  return l[0] + t*(l[0]-l[1]);
}
P reflection(const L& l, const P& p) {
  return p + 2.0*(projection(l, p) -p);
}
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]);
}
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;
}
bool convex_overlap(const VP &a, const VP &b){
    for(P p : a){
        if(in_poly(p, b) > 0) return true;
    }
    for(P p : b){
        if(in_poly(p, a) > 0) return true;
    }
    if(in_poly((a[0] +a[1] +a[2])/3.0, b) > 0 ||
       in_poly((b[0] +b[1] +b[2])/3.0, a) > 0){
        return true;
    }
    return false;
}

poly_connect fold_convex(int numl, int idx, poly_connect pc, const L& l){
    poly_connect ret;
    int n = pc.v.size();
    for(int i=0; i<n; i++){
        P curr = pc.v[i];
        P next = pc.v[(i+1)%n];
        if(ccw(l[0], l[1], curr) != -1){
            ret.v.push_back(curr);
            ret.c.push_back(pc.c[i]);
        }
        if(ccw(l[0], l[1], curr) *ccw(l[0], l[1], next) == -1){
            ret.v.push_back(crosspointLL(L(curr, next), l));
            if(ccw(l[0], l[1], curr) != -1){
                ret.c.push_back(2*numl-1-idx);
            }else{
                ret.c.push_back(pc.c[i]);
            }
        }
    }
    return ret;
}

poly_connect reverse_layer(int numl, poly_connect pc, const L &l){
    int n = pc.v.size();
    if(n == 0) return pc;
    for(int i=0; i<n; i++){
        pc.v[i] = reflection(l, pc.v[i]);
        if(pc.c[i] != -1){
            pc.c[i] = 2*numl -1 -pc.c[i];
        }
    }
    reverse(pc.v.begin()+1, pc.v.end());
    reverse(pc.c.begin(), pc.c.end());
    return pc;
}

void recursive_fold(int numl, int idx, vector<poly_connect> &ulayer, vector<bool> &used){
    if(idx >= numl || used[idx]) return;
    used[idx] = true;
    for(int connect : ulayer[idx].c){
        if(connect != -1){
            recursive_fold(numl, connect, ulayer, used);
        }
    }
    for(int i=idx+1; i<numl; i++){
        if(!ulayer[i].v.empty() && convex_overlap(ulayer[idx].v, ulayer[i].v)){
            recursive_fold(numl, i, ulayer, used);
        }
    }
}

void fold(int numl, vector<poly_connect> &layer, const P &p, const P &q){
    vector<poly_connect> dlayer(512), ulayer(512);
    P mid = (p +q) /2.0;
    L bisec(mid, mid +(q -p) *P(0, -1)); //残す方
    L rbisec(bisec[1], bisec[0]);
    for(int i=0; i<numl; i++){
        dlayer[i] = fold_convex(numl, i, layer[i], bisec);
        ulayer[i] = fold_convex(numl, i, layer[i], rbisec);
    }
    vector<bool> used(512, false);
    for(int i=numl-1; i>=0; i--){
        //一番上にあるlayerから再帰的に始める
        if(in_poly(p, layer[i].v) > 0){
            recursive_fold(numl, i, ulayer, used);
            break;
        }
    }
    for(int i=0; i<numl; i++){
        if(used[i]){
            layer[i] = dlayer[i];
            layer[2*numl-1-i] = reverse_layer(numl, ulayer[i], bisec);
        }
    }
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n == 0) break;

        VP p(n), q(n);
        for(int i=0; i<n; i++){
            int px,py, qx,qy;
            cin >> px >> py >> qx >> qy;
            p[i] = P(px, py);
            q[i] = P(qx, qy);
        }
        int hx,hy;
        cin >> hx >> hy;
        P h(hx, hy);

        vector<poly_connect> layer(1024);
        layer[0].v = VP{P(0, 0), P(100, 0), P(100, 100), P(0, 100)};
        layer[0].c = vector<int>{-1, -1, -1, -1};
        for(int i=0; i<n; i++){ 
            fold(1<<i, layer, p[i], q[i]);
        }
        int ans = 0;
        for(int i=0; i<(1<<n); i++){
            if(in_poly(h, layer[i].v) > 0){
                ans++;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3416
final_rank: 3

code_snippet: #include<cstdio>
#include<vector>
#include<complex>
#include<queue>
#include<utility>
#include<algorithm>

using namespace std;

typedef double Real;
typedef complex<Real> Point;
typedef pair<Point,Point> Line;
typedef pair<Point,Point> Segment;
typedef vector<Point> Polygon;

const Real eps=1e-7;
const Point NPoint=Point(NAN,NAN);
const Segment NSeg=Segment(NPoint,NPoint);

void print(Point p,char ch='\n'){
	//printf("(%f %f)%c",p.real(),p.imag(),ch);
}

void print(Polygon poly){
	/*if(poly.size()==0){
		printf("[empty]\n");
		return ;
	}
	for(int i=0;i<poly.size();i++){
		print(poly[i],' ');
	}
	printf("\n");*/
}

template<class T> bool eq(T a,T b){
	return abs(a-b)<eps;
}
template<class T> int sgn(T a){
	if(eq(a,0.0)) return 0;
	if(a>0) return 1;
	return -1;
}

bool onSeg(Point a,Point b,Point c){
	return eq(abs(a-b),abs(a-c)+abs(c-b));
}

Real doP(Point a,Point b){
	return (conj(a)*b).real();
}

Real crP(Point a,Point b){
	return (conj(a)*b).imag();
}

Point proj(Point p,Point b){
	return b*doP(p,b)/norm(b);
}

bool isPara_(Point a,Point b){
	return eq(crP(a,b),(Real)0);
}

Point iLL(Line l1,Line l2){
	if(isPara_(l1.second-l1.first,l2.second-l2.first)) return NPoint;
	Point a1=l1.first,b1=l1.second;
	Point a2=l2.first,b2=l2.second;
	Real num=crP(a2-a1,b1-a1);
	Real den=crP(b1-a1,b2-a2);
	return a2+(b2-a2)*(num/den);
}

bool iLS_(Line l,Segment s){
	if(isPara_(l.second-l.first,s.second-s.first)) return false;
	Point p=iLL(l,s);
	if(onSeg(s.first,s.second,p)) return true;
	return false;
}

Point iLS(Line l,Segment s){
	//重なるときは考えなくてよい 
	Point p=iLL(l,s);
	if(isnan(p.real())) return p;
	if(onSeg(s.first,s.second,p)) return p;
	return NPoint;
}

bool iSS_(Segment s1,Segment s2){
	Point p=iLL(s1,s2);
	if(isnan(p.real())) return false;
	if(!onSeg(s1.first,s1.second,p)) return false;
	if(!onSeg(s2.first,s2.second,p)) return false;
	return true;
}

Point iSS(Segment s1,Segment s2){
	if(iSS_(s1,s2)) return NPoint;
	return iLL(s1,s2);
}

Point perp(Line l,Point a){
	Point p=l.first,q=l.second;
	return p+proj(a-p,q-p);
}

Point refl(Line l,Point p){
	Point h=perp(l,p);
	return h*(Real)2-p;
}

Polygon refl(Line l,Polygon poly){
	Polygon res;
	for(int i=0;i<poly.size();i++){
		Point p=refl(l,poly[i]);
		res.push_back(p);
	}
	reverse(res.begin(),res.end());
	return res;
}

Segment refl(Line l,Segment seg){
	seg.first=refl(l,seg.first);
	seg.second=refl(l,seg.second);
	return seg;
}

Line perpBisec(Point p,Point q){
	Point d=q-p;
	Point rot=Point(0,1);
	Point mid=(p+q)/(Real)2;
	Point l1=mid+d*rot;
	Point l2=mid-d*rot;
	return Line(l1,l2);
}

Polygon convCut(Polygon poly,Point a,Point b){
	Polygon res;
	Line l=Line(a,b);
	if(poly.size()==0) return res;
	for(int i=0;i+1<poly.size();i++){
		if(sgn(crP(b-a,poly[i]-a))>=0) res.push_back(poly[i]);
		Segment seg=Segment(poly[i],poly[i+1]);
		if(iLS_(l,seg)){
			Point p=iLL(l,seg);
			if(eq(p,poly[i])) continue;
			if(eq(p,poly[i+1])) continue;
			res.push_back(iLL(l,seg));
		}
	}
	if(res.size()==0) return res;
	if(res.size()<=2){
		res.clear();
		return res;
	}
	res.push_back(res[0]);
	return res;
}

Segment iLPoly(Line l,Polygon poly){
	//1点で交わるとき注意!
	Segment seg=NSeg;
	for(int i=0;i+1<poly.size();i++){
		Segment e=Segment(poly[i],poly[i+1]);
		Point p=iLS(l,e);
		if(isnan(p.real())) continue;
		if(eq(p,poly[i+1])) continue;
		if(isnan(seg.first.real())) seg.first=p;
		else seg.second=p;
	}
	return seg;
}

bool inPoly_(Polygon poly,Point p){//ON is OUT
	bool in=false;
	for(int i=0;i+1<poly.size();i++){
		Point a=poly[i],b=poly[i+1];
		if(onSeg(a,b,p)) return false;
		a-=p,b-=p;
		if(sgn(a.imag()-b.imag())>0) swap(a,b);
		if(sgn(a.imag())<=0&&sgn(b.imag())>0){
			int s=sgn(crP(a,b));
			if(s==-1) in=!in;
		}
	}
	return in;
}

bool inPolyloose_(Polygon poly,Point p){//ON is IN
	bool in=false;
	for(int i=0;i+1<poly.size();i++){
		Point a=poly[i],b=poly[i+1];
		if(onSeg(a,b,p)) return true;
		a-=p,b-=p;
		if(sgn(a.imag()-b.imag())>0) swap(a,b);
		if(sgn(a.imag())<=0&&sgn(b.imag())>0){
			int s=sgn(crP(a,b));
			if(s==-1) in=!in;
		}
	}
	return in;
}	
/*
bool oPolyPoly_(Polygon p1,Polygon p2){
	//この場合は、zero area で重なることがないのでこれでよい 
	//よくなかった 
	//凸性を使っている 
	if(p1.empty()||p2.empty()) return false;
	if(inPoly_(p2,p1[0])) return true;
	if(inPoly_(p1,p2[0])) return true;/*
	for(int i=0;i+1<p1.size();i++){
		for(int j=0;j+1<p2.size();j++){
			Segment s1=Segment(p1[i],p1[i+1]);
			Segment s2=Segment(p2[j],p2[j+1]);
			bool flg=iSS_(s1,s2);
			if(flg) return true;
		}
	}*
	vector<Point> pts;
	for(int i=0;i+1<p1.size();i++){
		for(int j=0;j+1<p2.size();j++){
			Segment s1=Segment(p1[i],p1[i+1]);
			Segment s2=Segment(p2[j],p2[j+1]);
			Point p=iSS(s1,s2);
			if(isnan(p.real())) continue;
			if(eq(p,s1.first)||eq(p,s1.second)) continue;
			if(eq(p,s2.first)||eq(p,s2.second)) continue;
			pts.push_back(p);
		}
	}
	for(int i=0;i+1<p1.size();i++){
		if(inPolyloose_(p2,p1[i])) pts.push_back(p1[i]);
	}
	for(int j=0;j+1<p2.size();j++){
		bool ok=true;
		for(int i=0;i<p1.size();i++){
			if(eq(p1[i],p2[j])) ok=false;
		}
		if(!ok) continue;
		if(inPolyloose_(p1,p2[j])) pts.push_back(p2[j]);
	}
	if(pts.size()==0) return false;
	Point p=0;
	for(int i=0;i<pts.size();i++){
		p+=pts[i];
	}
	p/=(Real)pts.size();
	if(inPoly_(p1,p)==false) return false;
	if(inPoly_(p2,p)==false) return false;
	return true;
//	return false;
}*/

Polygon convCut(Polygon p1,Polygon p2){
	Polygon res=p1;
	for(int i=0;i+1<p2.size();i++){
		if(eq(p2[i],p2[i+1])) continue;
		res=convCut(res,p2[i],p2[i+1]);
	}
	return res;
}

bool oPolyPoly_(Polygon p1,Polygon p2){
	//凸のとき 
	if(p1.size()==0||p2.size()==0) return false;
	Polygon p=convCut(p1,p2);
	Real area=0;
	for(int i=0;i+1<p.size();i++){
		area+=crP(p[i],p[i+1]);
	}
	if(eq(area,(Real)0)) return false;
	else return true;
}

Polygon polys[1200];
Segment conSeg[1200][1200];
int V;

//Polygon old_polys[1200];
Polygon new_polys[1200];
int new_ids[1200];
vector<int> new_papers;
Segment new_conSeg[520][520];

bool folded[1200];

Segment tmp_conSeg[1200];

void process(Point p,Point q,bool last=false){
/*	printf("process\n");
	for(int i=0;i<V;i++){
		for(int j=0;j<V;j++){
			if(isnan(conSeg[i][j].first.real())) printf(".");
			else printf("#");
		}
		printf("\n");
	}*//*
	for(int i=0;i<V;i++){
		print(polys[i]);
	}*/
//	for(int i=0;i<V;i++) old_polys[i]=polys[i];
	for(int i=0;i<V;i++) new_polys[i]=polys[i];
	for(int i=0;i<V;i++) for(int j=0;j<V;j++){
		if(eq(conSeg[i][j].first,conSeg[i][j].second)){
			conSeg[i][j]=NSeg;
		}
	}
	Line l=perpBisec(p,q);//crP(p-l.first,l.second-l.first)>0
	for(int i=0;i<V;i++) tmp_conSeg[i]=iLPoly(l,polys[i]);
	for(int i=0;i<V;i++) for(int j=0;j<V;j++){
		if(i==j) continue;
		if(isnan(conSeg[i][j].first.real())){
			conSeg[i+V][j+V]=NSeg;
			continue;
		}
		Segment seg=conSeg[i][j];
		if(iLS_(l,seg)==false){
			Point tmp=seg.first;
			int s=sgn(crP(tmp-l.first,l.second-l.first));
			if(s==1){
				conSeg[i][j]=NSeg;
				conSeg[i+V][j+V]=seg;
			}else{
				conSeg[i][j]=seg;
				conSeg[i+V][j+V]=NSeg;
			}
		}else{
			Point s=iLL(l,seg);
			Point s1=seg.first,s2=seg.second;
			if(sgn(crP(s1-l.first,l.second-l.first))<0){
				swap(s1,s2);
			}
			conSeg[i+V][j+V]=Segment(s1,s);
			conSeg[i][j]=Segment(s,s2);
			if(eq(s1,s)){
				conSeg[i+V][j+V]=NSeg;
			}
			if(eq(s2,s)){
				conSeg[i][j]=NSeg;
			}
		}
	}
	for(int i=0;i<V;i++){
		Polygon poly=polys[i];
		polys[i]=convCut(poly,l.first,l.second);
		polys[i+V]=convCut(poly,l.second,l.first);
	}
//	printf("separated\n");
/*	for(int i=0;i<V*2;i++){
		print(polys[i]);
	}*/
//	printf("separated\n");
	int st=-1;
	for(int i=V*2-1;i>=V;i--){
		if(inPoly_(polys[i],p)){
			st=i;
			break;
		}
	}
	if(st==-1){
		printf("st=-1\n");
		exit(0);
	}
	for(int i=0;i<V*2;i++) folded[i]=false;
	folded[st]=true;
	queue<int> que;
	que.push(st);
	/*for(int i=0;i<V*2;i++){
		for(int j=0;j<V*2;j++){
			if(isnan(conSeg[i][j].first.real())) printf(".");
			else printf("#");
		}
		printf("\n");
	}*/
	while(!que.empty()){
		int cur=que.front();
		que.pop();
		for(int i=V;i<V*2;i++){
			if(i==cur) continue;
			if(folded[i]) continue;
			if(isnan(conSeg[i][cur].first.real())==false){
				folded[i]=true;
				que.push(i);
				continue;
			}
			if(i<cur) continue;
			bool flg=oPolyPoly_(polys[i],polys[cur]);
		//	if(overlap[i-V][cur-V]&&cur<i){
			if(flg){
				folded[i]=true;
				que.push(i);
			}
		}
	}
/*	printf("folded::");
	for(int i=0;i<V*2;i++){
		if(folded[i]) printf("%d ",i);
	}
	printf("\n");*/
	new_papers.clear();
	for(int i=0;i<V;i++){
	//	if(polys[i].empty()) continue;
		if(folded[i+V]==false){
			//new_polys[i]=old_polys[i];
			new_papers.push_back(i);
		}else{
			if(polys[i].size()>0){
				new_polys[i]=polys[i];
				new_papers.push_back(i);
			}
		}
	}
	for(int i=V*2-1;i>=V;i--){
		if(polys[i].empty()) continue;
		if(folded[i]){
			new_polys[i]=refl(l,polys[i]);
			new_papers.push_back(i);
		}
	}
	for(int i=0;i<V*2;i++){
		new_ids[i]=-1;
	}
	for(int i=0;i<new_papers.size();i++){
		new_ids[new_papers[i]]=i;
	}
	for(int i=0;i<V;i++){
		for(int j=0;j<V;j++){/*
			if(isnan(conSeg[i][j].first.real())==false&&isnan(conSeg[i+V][j+V].first.real())==false){
				if(folded[i+V]==false&&folded[j+V]==false){
					conSeg[i][j].first=conSeg[i+V][j+V].first;
				}
			}*/
			if(folded[i+V]==false&&folded[j+V]==false){
				if(isnan(conSeg[i+V][j+V].first.real())==false){
					if(conSeg[i][j].first.real()==false){
						conSeg[i][j].first=conSeg[i+V][j+V].first;
					}else{
						conSeg[i][j]=conSeg[i+V][j+V];
					}
				}else{
			//		conSeg[i][j]=conSeg[i+V][j+V];
				}
			}
		}
	}
	if(!last){
		for(int i=0;i<new_papers.size();i++) for(int j=i+1;j<new_papers.size();j++){
			int id1=new_papers[i];
			int id2=new_papers[j];
//			if(id2<V||id1>=V){
			if(id2<V){
				new_conSeg[i][j]=conSeg[id1][id2];
				new_conSeg[j][i]=conSeg[id2][id1];
			}else if(id1>=V){
				Segment tmp=conSeg[id1][id2];
				if(isnan(tmp.first.real())==false){
					tmp=refl(l,tmp);
				}
				new_conSeg[i][j]=tmp;
				new_conSeg[j][i]=tmp;
			}else if(id2-id1==V){
				//Segment seg=iLPoly(l,old_polys[id1]);
				Segment seg=tmp_conSeg[id1];
				new_conSeg[i][j]=seg;
				new_conSeg[j][i]=seg;
			}else{
				new_conSeg[i][j]=NSeg;
				new_conSeg[j][i]=NSeg;
			}
		}
	}
	V=new_papers.size();
	for(int i=0;i<V;i++) polys[i]=new_polys[new_papers[i]];
	if(!last){
		for(int i=0;i<V;i++) for(int j=0;j<V;j++){
			if(i==j) conSeg[i][j]=NSeg;
			else conSeg[i][j]=new_conSeg[i][j];
		}
/*		for(int i=0;i<V;i++) for(int j=0;j<V;j++){
			if(i==j) overlap[i][j]=false;
			else overlap[i][j]=oPolyPoly_(polys[i],polys[j]);
		}*/
	}
}

Point ps[10],qs[10];
Point h;
int N;

void input(){
	scanf("%d",&N);
	if(N==0) exit(0);
	for(int i=0;i<N;i++){
		int px,py,qx,qy;
		scanf("%d%d%d%d",&px,&py,&qx,&qy);
		ps[i]=Point(px,py);
		qs[i]=Point(qx,qy);
	}
	int x,y;
	scanf("%d%d",&x,&y);
	h=Point(x,y);
}

void init(){
	V=1;
	Point p1=Point(0,0);
	Point p2=Point(100,0);
	Point p3=Point(100,100);
	Point p4=Point(0,100);
	for(int i=0;i<1200;i++){
		polys[i].clear();
	//	old_polys[i].clear();
		new_polys[i].clear();
		for(int j=0;j<1200;j++){
			conSeg[i][j]=NSeg;
		//	overlap[i][j]=false;
		}
	}
	for(int i=0;i<520;i++) for(int j=0;j<520;j++){
		new_conSeg[i][j]=NSeg;
	}
	polys[0].push_back(p1);
	polys[0].push_back(p2);
	polys[0].push_back(p3);
	polys[0].push_back(p4);
	polys[0].push_back(p1);
}

void processAll(){
	for(int i=0;i<N;i++){
		Point p=ps[i],q=qs[i];
		if(i==N-1) process(p,q,true);
		else process(p,q);
	}
/*	printf("last V=%d\n",V);
	for(int i=0;i<V;i++){
		print(polys[i]);
	}*/
}

int getNum(){
	int res=0;
	for(int i=0;i<V;i++){
		if(inPoly_(polys[i],h)) res++;
	}
	return res;
}

int main(){
	while(true){
		input();
		init();
		processAll();
		int ans=getNum();
		printf("%d\n",ans);
	//	break;
	}
	return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 54852
final_rank: 4

code_snippet: #include <stdio.h>
#include <assert.h>
#include <iostream>
#include <complex>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(int)(n); i++)
#define mp make_pair
typedef complex<double> P;
typedef vector<P> convex;
#define EPS (1e-9)

double cross(const P& a, const P& b) { return imag(conj(a)*b); }
double dot(const P& a, const P& b) { return real(conj(a)*b); }

int ccw(const P& a, P b, P c) {
    b -= a; c -= a;
    if(cross(b, c)>0) return 1;
    if(cross(b, c)<0) return -1;
    if(dot(b, c)<0) return 2;
    if(norm(b)<norm(c)) return -2;
    return 0;
}

P projection(const P& l0, const P& l1, const P& p) {
    const double t = dot(p-l0, l1-l0) / norm(l1-l0);
    return l0 + t*(l1-l0);
}

bool intersectSP(const P& s0, const P& s1, const P& p) {
    return abs(s0-p)+abs(s1-p)-abs(s1-s0)<EPS;
}

P crosspoint(const P& l0, const P& l1, const P& m0, const P& m1) {
    const double a = cross(l1-l0, m1-m0);
    const double b = cross(l1-l0, l1-m0);
    if(abs(a)<EPS && abs(b)<EPS) return m0;
//    if(abs(a)<EPS) throw 0;
    return m0 + b/a*(m1-m0);
}

convex convex_cut(const convex& v, const P& l0, const P& l1) {
    convex r;
    rep(i, v.size()) {
        const P& a(v[i]), b(v[(i+1)%v.size()]);
        if(ccw(l0, l1, a)!=-1) r.push_back(a);
        if(ccw(l0, l1, a)*ccw(l0, l1, b)<0) {
            r.push_back(crosspoint(l0, l1, a, b));
        }
    }
    return r;
}

bool contains(const convex& ps, const P& p) {
    bool in = false;
    rep(i, ps.size()) {
        const int j = (i+1)%ps.size();
        P a(ps[i]-p), b(ps[j]-p);
        if(imag(a) > imag(b)) swap(a, b);
        if(imag(a) <= 0 && 0 < imag(b) && cross(a, b) < 0) in = !in;
        if(cross(a, b)==0 && dot(a, b) <= 0) return true; // on edge
    }
    return in;
}

bool intersectCVCV(const convex& a, const convex& b) {
    rep(i, a.size()) if(contains(b, a[i])) return true;
    rep(i, b.size()) if(contains(a, b[i])) return true;
    return false;
}

// convex and hinges
// hinges are represented by (1 + the index of the connected segment)
typedef pair<convex, vector<int> > segment;

int index(const convex& v, const P& s0, const P& s1) {
    const P& mid(0.5*(s0+s1));
    rep(i, v.size()) {
        const int j = (i+1)%v.size();
        if(intersectSP(v[i], v[j], mid)) return i;
    }
    return -1;
}

vector<segment> turnover(const vector<segment>& vs, P p, P q) {
    // first, determine which segments to turn over
    queue<int> qu;
    vector<int> is(vs.size(), 0);
    // rule 1
    for(int i=(int)vs.size()-1; i>=0; i--) if(contains(vs[i].first, p)) {
        qu.push(i);
        is[i] = 1;
        break;
    }
    P m(0.5*(p+q));
    P dir((p-q)*P(0, 1));
    while(!qu.empty()) {
        const int ix = qu.front();
        qu.pop();
        const convex& cv = vs[ix].first;
        convex a(convex_cut(cv, m, m-dir));
        // rule 2
        rep(i, a.size()) {
            const int j = (i+1)%a.size();
            const int k = index(cv, a[i], a[j]);
            if(k==-1) continue;
            const int tx = vs[ix].second[k]-1;
            if(tx!=-1 && !is[tx]) {
                qu.push(tx);
                is[tx] = 1;
            }
        }
        // rule 3
        for(int i=ix+1; i<(int)vs.size(); i++) {
            if(!is[i] && intersectCVCV(a, vs[i].first)) {
                qu.push(i);
                is[i] = 1;
            }
        }
    }

    // second, turn over the segments
    // in this section, hinges are left untouched, except for:
    //   hinges to segment in `s` -> positive
    //   hinges to segment in `t` -> negative
    vector<pair<int, segment> > s, t;
    rep(k, vs.size()) {
        if(is[k]==0) s.push_back(mp(k+1, vs[k]));
        else {
            const convex& cv = vs[k].first;
            convex a(convex_cut(cv, m, m+dir));
            if(a.size()>0) {
                vector<int> hg;
                rep(i, a.size()) {
                    const int j = (i+1)%a.size();
                    const int ix = index(cv, a[i], a[j]);
                    hg.push_back(ix==-1 ? -(k+1) : vs[k].second[ix]);
                }
                s.push_back(mp(k+1, mp(a, hg)));
            }
            convex b(convex_cut(cv, m, m-dir));
            if(b.size()>0) {
                vector<int> hg;
                rep(i, b.size()) {
                    const int j = (i-1+b.size())%b.size();
                    const int ix = index(cv, b[i], b[j]);
                    const P to = 2.0*projection(m, m+dir, b[i])-b[i];
                    hg.push_back(ix==-1 ? k+1 : -vs[k].second[ix]);
                }
                rep(i, b.size()) b[i] = 2.0*projection(m, m+dir, b[i])-b[i];
                reverse(b.begin(), b.end());
                reverse(hg.begin(), hg.end());
                t.push_back(mp(k+1, mp(b, hg)));
            }
        }
    }

    // third, fix the hinges
    map<int, int> of;
    rep(i, s.size()) of[s[i].first] = i+1;
    rep(i, t.size()) of[-t[i].first] = s.size()+t.size()-i;
    vector<segment> r;
    rep(i, s.size()) r.push_back(s[i].second);
    rep(i, t.size()) r.push_back(t[t.size()-1-i].second);
    rep(i, r.size()) rep(j, r[i].second.size()) {
        r[i].second[j] = of[r[i].second[j]];
    }
    return r;
}

int N, Px[16], Py[16], Qx[16], Qy[16];
int Hx, Hy;

int main() {
    for(;;) {
        scanf("%d", &N);
        if(N==0) return 0;
        rep(i, N) scanf("%d%d%d%d", Px+i, Py+i, Qx+i, Qy+i);
        scanf("%d%d", &Hx, &Hy);
        convex v;
        v.push_back(P(0, 0)); v.push_back(P(100, 0));
        v.push_back(P(100, 100)); v.push_back(P(0, 100));
        vector<segment> vs;
        vs.push_back(mp(v, vector<int>(v.size())));
        rep(i, N) vs = turnover(vs, P(Px[i], Py[i]), P(Qx[i], Qy[i]));
        int ans = 0;
        rep(i, vs.size()) if(contains(vs[i].first, P(Hx, Hy))) ans++;
        printf("%d\n", ans);
    }
}
accuracy: 1
time_ms: 20
memory_kb: 1140
final_rank: 1

code_snippet: #include <stdio.h>
#include <assert.h>
#include <iostream>
#include <complex>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;
#define rep(i, n) for(int i=0; i<(int)(n); i++)
#define mp make_pair
typedef complex<double> P;
typedef vector<P> convex;
typedef vector<pair<P, int> > segment;
#define EPS (1e-9)


double cross(const P& a, const P& b) { return imag(conj(a)*b); }
double dot(const P& a, const P& b) { return real(conj(a)*b); }

int ccw(const P& a, P b, P c) {
    b -= a; c -= a;
    if(cross(b, c)>0) return 1;
    if(cross(b, c)<0) return -1;
    if(dot(b, c)<0) return 2;
    if(norm(b)<norm(c)) return -2;
    return 0;
}

P projection(const P& l0, const P& l1, const P& p) {
    const double t = dot(p-l0, l1-l0) / norm(l1-l0);
    return l0 + t*(l1-l0);
}

bool intersectSP(const P& s0, const P& s1, const P& p) {
    return abs(s0-p)+abs(s1-p)-abs(s1-s0)<EPS;
}

P crosspoint(const P& l0, const P& l1, const P& m0, const P& m1) {
    const double a = cross(l1-l0, m1-m0);
    const double b = cross(l1-l0, l1-m0);
    if(abs(a)<EPS && abs(b)<EPS) return m0;
//    if(abs(a)<EPS) throw 0;
    return m0 + b/a*(m1-m0);
}

convex convex_cut(const convex& v, const P& l0, const P& l1) {
    convex r;
    rep(i, v.size()) {
        const P& a(v[i]), b(v[(i+1)%v.size()]);
        if(ccw(l0, l1, a)!=-1) r.push_back(a);
        if(ccw(l0, l1, a)*ccw(l0, l1, b)<0) {
            r.push_back(crosspoint(l0, l1, a, b));
        }
    }
    return r;
}

bool contains(const convex& ps, const P& p) {
    bool in = false;
    rep(i, ps.size()) {
        const int j = (i+1)%ps.size();
        P a(ps[i]-p), b(ps[j]-p);
        if(imag(a) > imag(b)) swap(a, b);
        if(imag(a) <= 0 && 0 < imag(b) && cross(a, b) < 0) in = !in;
        if(cross(a, b)==0 && dot(a, b) <= 0) return true; // on edge
    }
    return in;
}

convex to_convex(const segment& v) {
    convex r;
    rep(i, v.size()) r.push_back(v[i].first);
    return r;
}

int index(const convex& v, const P& s0, const P& s1) {
    const P& mid(0.5*(s0+s1));
    rep(i, v.size()) {
        const int j = (i+1)%v.size();
        if(intersectSP(v[i], v[j], mid)) return i;
    }
    return -1;
}

bool intersectCVCV(const convex& a, const convex& b) {
    rep(i, a.size()) if(contains(b, a[i])) return true;
    rep(i, b.size()) if(contains(a, b[i])) return true;
    return false;
}

vector<segment> turnover(const vector<segment>& vs, P p, P q) {
    queue<int> qu;
    for(int i=(int)vs.size()-1; i>=0; i--) {
        if(contains(to_convex(vs[i]), p)) {
            qu.push(i);
            break;
        }
    }
    P m(0.5*(p+q));
    P dir((p-q)*P(0, 1));
    vector<int> is(vs.size(), 0);
    while(!qu.empty()) {
        const int ix = qu.front();
        qu.pop();
        if(is[ix]) continue;
        is[ix] = 1;
        convex cv(to_convex(vs[ix]));
        convex a(convex_cut(cv, m, m-dir));
        for(int i=ix+1; i<(int)vs.size(); i++) if(!is[i]) {
            if(intersectCVCV(a, to_convex(vs[i]))) qu.push(i);
        }
        rep(i1, a.size()) {
            const int i2 = (i1+1)%a.size();
            const int k = index(cv, a[i1], a[i2]);
            if(k!=-1 && vs[ix][k].second!=-1) qu.push(vs[ix][k].second);
        }
    }
    vector<pair<int, segment> > s, t;
    rep(k, vs.size()) {
        if(is[k]==0) {
            segment sg;
            rep(i, vs[k].size()) {
                sg.push_back(mp(vs[k][i].first, vs[k][i].second+1));
            }
            s.push_back(mp(k+1, sg));
            continue;
        }
        convex cv(to_convex(vs[k]));
        convex a(convex_cut(cv, m, m+dir));
        if(a.size()>0) {
            segment as;
            rep(i, a.size()) {
                const int j = (i+1)%a.size();
                const int ix = index(cv, a[i], a[j]);
                as.push_back(mp(a[i], ix==-1 ? -(k+1) : vs[k][ix].second+1));
            }
            s.push_back(mp(k+1, as));
        }
        convex b(convex_cut(cv, m, m-dir));
        if(b.size()>0) {
            segment bs;
            rep(i, b.size()) {
                const int j = (i+1)%b.size();
                const int ix = index(cv, b[i], b[j]);
                const P to = 2.0*projection(m, m+dir, b[i])-b[i];
                bs.push_back(mp(to, ix==-1 ? k+1 : -(vs[k][ix].second+1)));
            }
            reverse(bs.begin(), bs.end());
            int x = bs[0].second;
            rep(i, bs.size()-1) bs[i].second = bs[i+1].second;
            bs.back().second = x;
            t.push_back(mp(k+1, bs));
        }
    }
    map<int, int> of;
    rep(i, s.size()) of[s[i].first] = i+1;
    rep(i, t.size()) of[-t[i].first] = s.size()+t.size()-i;
    vector<segment> r;
    rep(i, s.size()) r.push_back(s[i].second);
    rep(i, t.size()) r.push_back(t[t.size()-1-i].second);
    rep(i, r.size()) rep(j, r[i].size()) r[i][j].second = of[r[i][j].second]-1;
    return r;
}

int N, Px[16], Py[16], Qx[16], Qy[16];
int Hx, Hy;

int main() {
    for(;;) {
        scanf("%d", &N);
        if(N==0) return 0;
        rep(i, N) scanf("%d%d%d%d", Px+i, Py+i, Qx+i, Qy+i);
        scanf("%d%d", &Hx, &Hy);
        vector<pair<P, int> > v;
        v.push_back(mp(P(0, 0), -1));
        v.push_back(mp(P(100, 0), -1));
        v.push_back(mp(P(100, 100), -1));
        v.push_back(mp(P(0, 100), -1));
        vector<vector<pair<P, int> > > vs;
        vs.push_back(v);
        rep(i, N) vs = turnover(vs, P(Px[i], Py[i]), P(Qx[i], Qy[i]));
        int ans = 0;
        rep(i, vs.size()) if(contains(to_convex(vs[i]), P(Hx, Hy))) ans++;
        printf("%d\n", ans);
    }
}
accuracy: 1
time_ms: 90
memory_kb: 1500
final_rank: 2

code_snippet: #include<iostream>
#include<queue>
#include<vector>
#include<complex>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
const double eps = 1e-10;

const int N = 2000;

typedef complex<double> P;

bool adj[N][N];
bool up[N][N];//up[i][j] = 1 i >=j 
bool cpyadj[N][N];
bool cpyup[N][N];

class Polygon{
public:
  vector<P> ori,newp;
  int oriid,newid;
  int cutbit;
  vector<P> inipos;
};

void outputpolygon(vector<P> &a){
  cout << "[";
  rep(i,a.size()+1)cout << a[(i+1)%a.size()]<<",";
  cout << "],"<<endl;
}


#define RIGHT 1
#define LEFT -1

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}

bool isp(P &a,P &b,P &c){
  return abs(a-c)+abs(b-c) < abs(a-b) + eps;
}

P intersection_ll(P &a1,P &a2,P &b1,P &b2){
  P a=a2-a1,b=b2-b1;
  return a1+ a*cross(b,b1-a1)/cross(b,a);
}

int ccw(P a,P b){
  if (cross(a,b)    < -0)return RIGHT;
  else if(cross(a,b)>  0)return LEFT;
  return 2;
}

bool is_intersected_ls(P &a1,P &a2,P &b1,P &b2){
  if (isp(a1,a2,b1)||isp(a1,a2,b2)||isp(b1,b2,a1)||
      isp(b1,b2,a2))return true;
  if (cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<-eps &&
      cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<-eps)
    return true;
  return false;
}

//LEFT remain,RIGHT reflect
void Convex_cut(vector<P> in,P &a1,P &a2,
		vector<P> &ori,vector<P> &newp){
  int n = in.size();
  ori.clear();newp.clear();
  rep(i,n){
    P now = in[i],next=in[(i+1)%n];
    if( ccw(a1-a2,now-a2) == LEFT)ori.pb(now);
    else if( ccw(a1-a2,now-a2) == RIGHT)newp.pb(now);
    if (ccw(a1-a2,now-a2)*ccw(a1-a2,next-a2)<0){
      ori.pb(intersection_ll(a1,a2,now,next));
      newp.pb(intersection_ll(a1,a2,now,next));
    }
  }
}

pair<P,P> make_line(P p,P q){
  int cutpos=RIGHT;
  P tmp=(p+q);
  tmp.real()/=2;tmp.imag()/=2;
  P ret=q-tmp;
  swap(ret.real(),ret.imag());
  ret.real()*=-1;
  if ( ccw(ret,p-tmp) != cutpos)return make_pair(tmp,ret+tmp);
  return make_pair(ret+tmp,tmp);
}

bool is_in(vector<P> &in,P &a){
  int cnt=0;
  int n = in.size();
  rep(i,n){
    P cur = in[i]-a,next=in[(i+1)%n]-a;
    if (cur.imag()>next.imag())swap(cur,next);
    if (cur.imag()<0&&0<=next.imag()&&
	cross(next,cur)>= 0)cnt++;
    if (isp(in[i],in[(i+1)%n],a))return true;
  }

  if (cnt%2 == 1)return true;
  return false;
}

P reflect(P &o,P &p,P &q){
  P N=p-o,L=q-o;
  double t = abs(L);
  N/=abs(N);
  L/=abs(L);
  double prepL = dot(N,L);//theta element of vector L against N (|L|=|N|=1
  double d=2*prepL;
  P r(d*N - L);//R vector symmetric point of L
  return o+t*r;
}

int find_most_upper(int n,Polygon *in,P &p){
  int index = -1;
  rep(i,n){
    if (is_in(in[i].ori,p)){
      if (index == -1)index =i;
      else if (up[i][index])index=i;
    }
  }
  return index;
}

//a ori,b newp
bool is_intersected_polygon(vector<P> &a,vector<P> &b){
  rep(i,a.size()){
    if (is_in(b,a[i]))return true;
    rep(j,b.size()){
      if (is_intersected_ls(a[i],a[(i+1)%a.size()],
			    b[j],b[(j+1)%b.size()])){
	return true;
      }
    }
  }
  rep(j,b.size())if (is_in(a,b[j]))return true;
  return false;
}


double distance_l_p(P a,P b,P c){
  return abs( cross(b-a,c-a))/abs(b-a);
}

bool issame(P &a,P &b){
  return fabs(a.real()-b.real())<eps && fabs(a.imag()-b.imag())<eps;
}

bool have_same_line(vector<P> &in1,vector<P> &in2,P &a,P &b,bool flag){
  rep(i,in1.size()){
    rep(j,in2.size()){
      if (isp(in1[i],in1[(i+1)%in1.size()],in2[j])
	  ||isp(in1[i],in1[(i+1)%in1.size()],in2[(j+1)%in2.size()])
	  )return true;

      if ((issame(in1[i],in2[j])&&issame(in1[(i+1)%in1.size()],in2[(j+1)%in2.size()]))
	||
	(issame(in1[i],in2[(j+1)%in2.size()])&&issame(in1[(i+1)%in1.size()],in2[j]))
	)return true;
    }
  }
  return false;
}

bool vis[N];
void origami(int &n,int ini,Polygon in[N],P &a,P &b,
	     pair<P,P> *line,int querry){
  int m = n;
  vector<P> dummy;
  rep(i,N){
    in[i].newp.clear(),in[i].newid=-1;//nen no tame
  }

  rep(i,N)vis[i]=false;
  queue<int> Q;
  Q.push(ini);
  while(!Q.empty()){
    int now = Q.front();Q.pop();
    if (vis[now])continue;
    
    vis[now]=true;

    Convex_cut(in[now].ori,a,b,in[now].ori,in[now].newp);
    if (in[now].newp.size() != 0){
      in[now].oriid=now;
      in[now].newid=m++;
      in[in[now].newid].cutbit=in[now].cutbit|(1<<querry);
    }
    
    
    in[now].inipos=in[now].newp;
    for(int j=querry-1;j>=0;j--){
      if((in[now].cutbit&(1<<j)) != 0){
	rep(k,in[now].inipos.size()){
	  in[now].inipos[k]=reflect(line[j].first,line[j].second,in[now].inipos[k]);
	}
      }
    }
    
    
    rep(i,n){
      if (i == now)continue;
      if (adj[now][i]){
	if(have_same_line(in[now].inipos,in[i].inipos,a,b,false))
	  Q.push(i);
      }
      if (up[i][now]){
	if (is_intersected_polygon(in[now].newp,in[i].ori))
	  Q.push(i);
      }
    }
  }
  
  rep(i,n){
    rep(j,in[i].newp.size()){
      in[i].newp[j]=reflect(a,b,in[i].newp[j]);
    }
  }
  

  rep(i,n){
    int myori=in[i].oriid,mynew=in[i].newid;
    if (in[i].newp.size() == 0)mynew=-1;
    
    if (mynew != -1){
      up[myori][mynew]=false;
      up[mynew][myori]=true;
    }
    
    rep(j,n){
      if (i == j)continue;
      int yori=in[j].oriid,yournew=in[j].newid;
      bool tmp = up[i][j];
      //in[i].ori-in[j].ori
      up[myori][yori]=up[myori][yori];

      //in[i].ori-in[j].newp
      if (yournew != -1){
	up[myori][yournew]=false;
      }

      //in[i].newp-in[j].ori
      if (mynew != -1){
	if (is_intersected_polygon(in[i].newp,in[j].ori)){
	  up[mynew][yori]=true;
	}else {
	  up[mynew][yori]=false;
	}
      }
 
      //in[i].newp-in[j].ori
      if (mynew != -1 && yournew != -1){
	if (up[yori][myori] && is_intersected_polygon(in[i].newp,in[j].newp))
	  up[mynew][yournew]=true;
	else up[mynew][yournew]=false;
      }
    }
  }
        
    
    
  rep(i,n){
    if (in[i].newp.size() != 0){
      in[in[i].newid].ori=in[i].newp;
      in[in[i].newid].oriid=in[i].newid;
      in[i].newp.clear();
    }
  }

  n = m;

  rep(i,m){
    in[i].inipos.clear();
    in[i].inipos=in[i].ori;
    for(int j=querry;j>=0;j--){
      if((in[i].cutbit&(1<<j)) != 0){
	rep(k,in[i].inipos.size()){
	  in[i].inipos[k]=reflect(line[j].first,line[j].second,in[i].inipos[k]);
	}
      }
    }
  }

  rep(i,m){
    REP(j,i+1,m){
      if (have_same_line(in[i].inipos,in[j].inipos,a,b,true)){
	adj[i][j]=adj[j][i]=true;
      }else adj[i][j]=adj[j][i]=false;
    }
  }
}
	     
int solve(int querry){
  int n=1;
  static Polygon in[N];
  pair<P,P> line[10];
  P pos[10];
  // initialization
  rep(i,N){
    in[i].ori.clear();
    in[i].newp.clear();
    in[i].inipos.clear();
    in[i].oriid=i;
    in[i].newid=-1;
    in[i].cutbit=0;
  }
  rep(i,N)rep(j,N)adj[i][j]=false,up[i][j]=false;
  
  in[0].ori.pb(P(0,0));
  in[0].ori.pb(P(0,100));
  in[0].ori.pb(P(100,100));
  in[0].ori.pb(P(100,0));
  in[0].inipos=in[0].ori;

  rep(i,querry){
    P p,q;
    cin>>p.real()>>p.imag()>>q.real()>>q.imag();
    pos[i]=p;
    pair<P,P> tmp;
    line[i] = make_line(p,q);
  }

  rep(i,querry){
    int index = find_most_upper(n,in,pos[i]);
    if (index == -1){
    }else origami(n,index,in,line[i].first,line[i].second,
		  line,i);
  }

  
  int cnt=0;
  P hole;
  cin>>hole.real()>>hole.imag();
  rep(i,n){
    if (in[i].ori.size() && is_in(in[i].ori,hole))cnt++;
  }

  return cnt;
}

main(){
  int q;
  while(cin>>q&&q){
    cout << solve(q) << endl; 
  }
}
accuracy: 1
time_ms: 4920
memory_kb: 9588
final_rank: 5

code_snippet: #include<iostream>
#include<queue>
#include<vector>
#include<complex>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
const double eps = 1e-10;

const int N = 2000;

typedef complex<double> P;

bool adj[N][N];
bool up[N][N];//up[i][j] = 1 i >=j 
bool cpyadj[N][N];
bool cpyup[N][N];

class Polygon{
public:
  vector<P> ori,newp;
  int oriid,newid;
  int cutbit;
  vector<P> inipos;
};

void outputpolygon(vector<P> &a){
  cout << "[";
  rep(i,a.size()+1)cout << a[(i+1)%a.size()]<<",";
  cout << "],"<<endl;
}


#define RIGHT 1
#define LEFT -1

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}

bool isp(P &a,P &b,P &c){
  return abs(a-c)+abs(b-c) < abs(a-b) + eps;
}

P intersection_ll(P &a1,P &a2,P &b1,P &b2){
  P a=a2-a1,b=b2-b1;
  return a1+ a*cross(b,b1-a1)/cross(b,a);
}

int ccw(P a,P b){
  if (cross(a,b)    < -0)return RIGHT;
  else if(cross(a,b)>  0)return LEFT;
  return 2;
}

bool is_intersected_ls(P &a1,P &a2,P &b1,P &b2){
  if (isp(a1,a2,b1)||isp(a1,a2,b2)||isp(b1,b2,a1)||
      isp(b1,b2,a2))return true;
  if (cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<-eps &&
      cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<-eps)
    return true;
  return false;
}

//LEFT remain,RIGHT reflect
void Convex_cut(vector<P> in,P &a1,P &a2,
		vector<P> &ori,vector<P> &newp){
  int n = in.size();
  ori.clear();newp.clear();
  rep(i,n){
    P now = in[i],next=in[(i+1)%n];
    if( ccw(a1-a2,now-a2) == LEFT)ori.pb(now);
    else if( ccw(a1-a2,now-a2) == RIGHT)newp.pb(now);
    if (ccw(a1-a2,now-a2)*ccw(a1-a2,next-a2)<0){
      //ori.pb(intersection_ll(a1,a2,now,next));
      ori.pb(intersection_ll(now,next,a1,a2));
      newp.pb(intersection_ll(a1,a2,now,next));
    }
  }
}

pair<P,P> make_line(P p,P q){
  int cutpos=RIGHT;
  P tmp=(p+q);
  tmp.real()/=2;tmp.imag()/=2;
  P ret=q-tmp;
  swap(ret.real(),ret.imag());
  ret.real()*=-1;
  if ( ccw(ret,p-tmp) != cutpos)return make_pair(tmp,ret+tmp);
  return make_pair(ret+tmp,tmp);
}

bool is_in(vector<P> &in,P &a){
  int cnt=0;
  int n = in.size();
  rep(i,n){
    P cur = in[i]-a,next=in[(i+1)%n]-a;
    if (cur.imag()>next.imag())swap(cur,next);
    if (cur.imag()<0&&0<=next.imag()&&
	cross(next,cur)>= 0)cnt++;
    if (isp(in[i],in[(i+1)%n],a))return true;
  }

  if (cnt%2 == 1)return true;
  return false;
}

P reflect(P &o,P &p,P &q){
  P N=p-o,L=q-o;
  double t = abs(L);
  N/=abs(N);
  L/=abs(L);
  double prepL = dot(N,L);//theta element of vector L against N (|L|=|N|=1
  double d=2*prepL;
  P r(d*N - L);//R vector symmetric point of L
  return o+t*r;
}

int find_most_upper(int n,Polygon *in,P &p){
  int index = -1;
  rep(i,n){
    if (is_in(in[i].ori,p)){
      if (index == -1)index =i;
      else if (up[i][index])index=i;
    }
  }
  return index;
}

//a ori,b newp
bool is_intersected_polygon(vector<P> &a,vector<P> &b){
  rep(i,a.size()){
    if (is_in(b,a[i]))return true;
    rep(j,b.size()){
      if (is_intersected_ls(a[i],a[(i+1)%a.size()],
			    b[j],b[(j+1)%b.size()])){
	return true;
      }
    }
  }
  rep(j,b.size())if (is_in(a,b[j]))return true;
  return false;
}


double distance_l_p(P a,P b,P c){
  return abs( cross(b-a,c-a))/abs(b-a);
}

bool issame(P &a,P &b){
  return fabs(a.real()-b.real())<eps && fabs(a.imag()-b.imag())<eps;
}

bool have_same_line(vector<P> &in1,vector<P> &in2,P &a,P &b,bool flag){
  rep(i,in1.size()){
    rep(j,in2.size()){
      if (isp(in1[i],in1[(i+1)%in1.size()],in2[j])
	  ||isp(in1[i],in1[(i+1)%in1.size()],in2[(j+1)%in2.size()])
	  )return true;

      if ((issame(in1[i],in2[j])&&issame(in1[(i+1)%in1.size()],in2[(j+1)%in2.size()]))
	||
	(issame(in1[i],in2[(j+1)%in2.size()])&&issame(in1[(i+1)%in1.size()],in2[j]))
	)return true;
    }
  }
  return false;
}

bool vis[N];
void origami(int &n,int ini,Polygon in[N],P &a,P &b,
	     pair<P,P> *line,int querry){
  int m = n;
  vector<P> dummy;
  rep(i,N){
    in[i].newp.clear(),in[i].newid=-1;//nen no tame
  }

  rep(i,N)vis[i]=false;
  queue<int> Q;
  Q.push(ini);
  while(!Q.empty()){
    int now = Q.front();Q.pop();
    if (vis[now])continue;
    
    vis[now]=true;

    Convex_cut(in[now].ori,a,b,in[now].ori,in[now].newp);
    if (in[now].newp.size() != 0){
      in[now].oriid=now;
      in[now].newid=m++;
      in[in[now].newid].cutbit=in[now].cutbit|(1<<querry);
    }
    
    
    in[now].inipos=in[now].newp;
    for(int j=querry-1;j>=0;j--){
      if((in[now].cutbit&(1<<j)) != 0){
	rep(k,in[now].inipos.size()){
	  in[now].inipos[k]=reflect(line[j].first,line[j].second,in[now].inipos[k]);
	}
      }
    }
    
    
    rep(i,n){
      if (i == now)continue;
      if (adj[now][i]){
	if(have_same_line(in[now].inipos,in[i].inipos,a,b,false))
	  Q.push(i);
      }
      if (up[i][now]){
	if (is_intersected_polygon(in[now].newp,in[i].ori))
	  Q.push(i);
      }
    }
  }
  
  rep(i,n){
    rep(j,in[i].newp.size()){
      in[i].newp[j]=reflect(a,b,in[i].newp[j]);
    }
  }
  

  rep(i,n){
    int myori=in[i].oriid,mynew=in[i].newid;
    if (in[i].newp.size() == 0)mynew=-1;
    
    if (mynew != -1){
      up[myori][mynew]=false;
      up[mynew][myori]=true;
    }
    
    rep(j,n){
      if (i == j)continue;
      int yori=in[j].oriid,yournew=in[j].newid;
      bool tmp = up[i][j];
      //in[i].ori-in[j].ori
      up[myori][yori]=up[myori][yori];

      //in[i].ori-in[j].newp
      if (yournew != -1){
	up[myori][yournew]=false;
      }

      //in[i].newp-in[j].ori
      if (mynew != -1){
	if (is_intersected_polygon(in[i].newp,in[j].ori)){
	  up[mynew][yori]=true;
	}else {
	  up[mynew][yori]=false;
	}
      }
 
      //in[i].newp-in[j].ori
      if (mynew != -1 && yournew != -1){
	if (up[yori][myori] && is_intersected_polygon(in[i].newp,in[j].newp))
	  up[mynew][yournew]=true;
	else up[mynew][yournew]=false;
      }
    }
  }
        
    
    
  rep(i,n){
    if (in[i].newp.size() != 0){
      in[in[i].newid].ori=in[i].newp;
      in[in[i].newid].oriid=in[i].newid;
      in[i].newp.clear();
    }
  }

  n = m;

  rep(i,m){
    in[i].inipos.clear();
    in[i].inipos=in[i].ori;
    for(int j=querry;j>=0;j--){
      if((in[i].cutbit&(1<<j)) != 0){
	rep(k,in[i].inipos.size()){
	  in[i].inipos[k]=reflect(line[j].first,line[j].second,in[i].inipos[k]);
	}
      }
    }
  }

  rep(i,m){
    REP(j,i+1,m){
      if (have_same_line(in[i].inipos,in[j].inipos,a,b,true)){
	adj[i][j]=adj[j][i]=true;
      }else adj[i][j]=adj[j][i]=false;
    }
  }
}
	     
int solve(int querry){
  int n=1;
  static Polygon in[N];
  pair<P,P> line[10];
  P pos[10];
  // initialization
  rep(i,N){
    in[i].ori.clear();
    in[i].newp.clear();
    in[i].inipos.clear();
    in[i].oriid=i;
    in[i].newid=-1;
    in[i].cutbit=0;
  }
  rep(i,N)rep(j,N)adj[i][j]=false,up[i][j]=false;
  
  in[0].ori.pb(P(0,0));
  in[0].ori.pb(P(0,100));
  in[0].ori.pb(P(100,100));
  in[0].ori.pb(P(100,0));
  in[0].inipos=in[0].ori;

  rep(i,querry){
    P p,q;
    cin>>p.real()>>p.imag()>>q.real()>>q.imag();
    pos[i]=p;
    pair<P,P> tmp;
    line[i] = make_line(p,q);
  }

  rep(i,querry){
    int index = find_most_upper(n,in,pos[i]);
    if (index == -1){
    }else origami(n,index,in,line[i].first,line[i].second,
		  line,i);
  }

  
  int cnt=0;
  P hole;
  cin>>hole.real()>>hole.imag();
  rep(i,n){
    if (in[i].ori.size() && is_in(in[i].ori,hole))cnt++;
  }

  return cnt;
}

main(){
  int q;
  while(cin>>q&&q){
    cout << solve(q) << endl; 
  }
}
accuracy: 1
time_ms: 4930
memory_kb: 9584
final_rank: 6

code_snippet: #include<iostream>
#include<queue>
#include<vector>
#include<complex>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
const double eps = 1e-10;

const int N = 2000;

typedef complex<double> P;

bool adj[N][N];
bool up[N][N];//up[i][j] = 1 i >=j 
bool cpyadj[N][N];
bool cpyup[N][N];

class Polygon{
public:
  vector<P> ori,newp;
  int oriid,newid;
  int cutbit;
  vector<P> inipos;
};

void outputpolygon(vector<P> &a){
  cout << "[";
  rep(i,a.size()+1)cout << a[(i+1)%a.size()]<<",";
  cout << "],"<<endl;
}


#define RIGHT 1
#define LEFT -1

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}

bool isp(P &a,P &b,P &c){
  return abs(a-c)+abs(b-c) < abs(a-b) + eps;
}

P intersection_ll(P &a1,P &a2,P &b1,P &b2){
  P a=a2-a1,b=b2-b1;
  return a1+ a*cross(b,b1-a1)/cross(b,a);
}

int ccw(P a,P b){
  if (cross(a,b)    < -0)return RIGHT;
  else if(cross(a,b)>  0)return LEFT;
  return 2;
}

bool is_intersected_ls(P &a1,P &a2,P &b1,P &b2){
  if (isp(a1,a2,b1)||isp(a1,a2,b2)||isp(b1,b2,a1)||
      isp(b1,b2,a2))return true;
  if (cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<-eps &&
      cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<-eps)
    return true;
  return false;
}

//LEFT remain,RIGHT reflect
void Convex_cut(vector<P> in,P &a1,P &a2,
		vector<P> &ori,vector<P> &newp){
  int n = in.size();
  ori.clear();newp.clear();
  rep(i,n){
    P now = in[i],next=in[(i+1)%n];
    if( ccw(a1-a2,now-a2) == LEFT)ori.pb(now);
    else if( ccw(a1-a2,now-a2) == RIGHT)newp.pb(now);
    if (ccw(a1-a2,now-a2)*ccw(a1-a2,next-a2)<0){
      ori.pb(intersection_ll(a1,a2,now,next));
      newp.pb(intersection_ll(a1,a2,now,next));
    }
  }
}

pair<P,P> make_line(P p,P q){
  int cutpos=RIGHT;
  P tmp=(p+q);
  tmp.real()/=2;tmp.imag()/=2;
  P ret=q-tmp;
  swap(ret.real(),ret.imag());
  ret.real()*=-1;
  if ( ccw(ret,p-tmp) != cutpos)return make_pair(tmp,ret+tmp);
  return make_pair(ret+tmp,tmp);
}

bool is_in(vector<P> &in,P &a){
  int cnt=0;
  int n = in.size();
  rep(i,n){
    P cur = in[i]-a,next=in[(i+1)%n]-a;
    if (cur.imag()>next.imag())swap(cur,next);
    if (cur.imag()<0&&0<=next.imag()&&
	cross(next,cur)>= 0)cnt++;
    if (isp(in[i],in[(i+1)%n],a))return true;
  }

  if (cnt%2 == 1)return true;
  return false;
}

P reflect(P &o,P &p,P &q){
  P N=p-o,L=q-o;
  double t = abs(L);
  N/=abs(N);
  L/=abs(L);
  double prepL = dot(N,L);//theta element of vector L against N (|L|=|N|=1
  double d=2*prepL;
  P r(d*N - L);//R vector symmetric point of L
  return o+t*r;
}

int find_most_upper(int n,Polygon *in,P &p){
  int index = -1;
  rep(i,n){
    if (is_in(in[i].ori,p)){
      if (index == -1)index =i;
      else if (up[i][index])index=i;
    }
  }
  return index;
}

//a ori,b newp
bool is_intersected_polygon(vector<P> &a,vector<P> &b){
  rep(i,a.size()){
    if (is_in(b,a[i]))return true;
    rep(j,b.size()){
      if (is_intersected_ls(a[i],a[(i+1)%a.size()],
			    b[j],b[(j+1)%b.size()])){
	return true;
      }
    }
  }
  rep(j,b.size())if (is_in(a,b[j]))return true;
  return false;
}


double distance_l_p(P a,P b,P c){
  return abs( cross(b-a,c-a))/abs(b-a);
}

bool issame(P &a,P &b){
  return fabs(a.real()-b.real())<eps && fabs(a.imag()-b.imag())<eps;
}

bool have_same_line(vector<P> &in1,vector<P> &in2,P &a,P &b,bool flag){
  rep(i,in1.size()){
    rep(j,in2.size()){
      if (isp(in1[i],in1[(i+1)%in1.size()],in2[j])
	  ||isp(in1[i],in1[(i+1)%in1.size()],in2[(j+1)%in2.size()])
	  )return true;

      if ((issame(in1[i],in2[j])&&issame(in1[(i+1)%in1.size()],in2[(j+1)%in2.size()]))
	||
	(issame(in1[i],in2[(j+1)%in2.size()])&&issame(in1[(i+1)%in1.size()],in2[j]))
	)return true;
    }
  }
  return false;
}

bool vis[N];
void origami(int &n,int ini,Polygon in[N],P &a,P &b,
	     pair<P,P> *line,int querry){
  int m = n;
  vector<P> dummy;
  rep(i,N){
    in[i].newp.clear(),in[i].newid=-1;//nen no tame
  }

  rep(i,N)vis[i]=false;
  queue<int> Q;
  Q.push(ini);
  while(!Q.empty()){
    int now = Q.front();Q.pop();
    if (vis[now])continue;
    
    vis[now]=true;

    Convex_cut(in[now].ori,a,b,in[now].ori,in[now].newp);
    if (in[now].newp.size() != 0){
      in[now].oriid=now;
      in[now].newid=m++;
      in[in[now].newid].cutbit=in[now].cutbit|(1<<querry);
    }
    
    
    in[now].inipos=in[now].newp;
    for(int j=querry-1;j>=0;j--){
      if((in[now].cutbit&(1<<j)) != 0){
	rep(k,in[now].inipos.size()){
	  in[now].inipos[k]=reflect(line[j].first,line[j].second,in[now].inipos[k]);
	}
      }
    }
    
    
    rep(i,n){
      if (i == now)continue;
      if (adj[now][i]){
	if(have_same_line(in[now].inipos,in[i].inipos,a,b,false))
	  Q.push(i);
      }
      if (up[i][now]){
	if (is_intersected_polygon(in[now].newp,in[i].ori))
	  Q.push(i);
      }
    }
  }
  
  rep(i,n){
    rep(j,in[i].newp.size()){
      in[i].newp[j]=reflect(a,b,in[i].newp[j]);
    }
  }
  

  rep(i,n){
    int myori=in[i].oriid,mynew=in[i].newid;
    if (in[i].newp.size() == 0)mynew=-1;
    
    if (mynew != -1){
      up[myori][mynew]=false;
      up[mynew][myori]=true;
    }
    
    rep(j,n){
      if (i == j)continue;
      int yourori=in[j].oriid,yournew=in[j].newid;
      bool tmp = up[i][j];
      //in[i].ori-in[j].ori
      up[myori][yourori]=up[myori][yourori];

      //in[i].ori-in[j].newp
      if (yournew != -1){
	up[myori][yournew]=false;
      }

      //in[i].newp-in[j].ori
      if (mynew != -1){
	if (is_intersected_polygon(in[i].newp,in[j].ori)){
	  up[mynew][yourori]=true;
	}else {
	  up[mynew][yourori]=false;
	}
      }
 
      //in[i].newp-in[j].ori
      if (mynew != -1 && yournew != -1){
	if (up[yourori][myori] && is_intersected_polygon(in[i].newp,in[j].newp))
	  up[mynew][yournew]=true;
	else up[mynew][yournew]=false;
      }
    }
  }
        
    
    
  rep(i,n){
    if (in[i].newp.size() != 0){
      in[in[i].newid].ori=in[i].newp;
      in[in[i].newid].oriid=in[i].newid;
      in[i].newp.clear();
    }
  }

  n = m;

  rep(i,m){
    in[i].inipos.clear();
    in[i].inipos=in[i].ori;
    for(int j=querry;j>=0;j--){
      if((in[i].cutbit&(1<<j)) != 0){
	rep(k,in[i].inipos.size()){
	  in[i].inipos[k]=reflect(line[j].first,line[j].second,in[i].inipos[k]);
	}
      }
    }
  }

  rep(i,m){
    REP(j,i+1,m){
      if (have_same_line(in[i].inipos,in[j].inipos,a,b,true)){
	adj[i][j]=adj[j][i]=true;
      }else adj[i][j]=adj[j][i]=false;
    }
  }
}
	     
int solve(int querry){
  int n=1;
  static Polygon in[N];
  pair<P,P> line[10];
  P pos[10];
  // initialization
  rep(i,N){
    in[i].ori.clear();
    in[i].newp.clear();
    in[i].inipos.clear();
    in[i].oriid=i;
    in[i].newid=-1;
    in[i].cutbit=0;
  }
  rep(i,N)rep(j,N)adj[i][j]=false,up[i][j]=false;
  
  in[0].ori.pb(P(0,0));
  in[0].ori.pb(P(0,100));
  in[0].ori.pb(P(100,100));
  in[0].ori.pb(P(100,0));
  in[0].inipos=in[0].ori;

  rep(i,querry){
    P p,q;
    cin>>p.real()>>p.imag()>>q.real()>>q.imag();
    pos[i]=p;
    pair<P,P> tmp;
    line[i] = make_line(p,q);
  }

  rep(i,querry){
    int index = find_most_upper(n,in,pos[i]);
    if (index == -1){
    }else origami(n,index,in,line[i].first,line[i].second,
		  line,i);
  }

  
  int cnt=0;
  P hole;
  cin>>hole.real()>>hole.imag();
  rep(i,n){
    if (in[i].ori.size() && is_in(in[i].ori,hole))cnt++;
  }

  return cnt;
}

main(){
  int q;
  while(cin>>q&&q){
    cout << solve(q) << endl; 
  }
}
accuracy: 1
time_ms: 4930
memory_kb: 9584
final_rank: 6

code_snippet: #include<iostream>
#include<queue>
#include<vector>
#include<complex>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define pb         push_back
const double eps = 1e-10;

const int N = 2000;

typedef complex<double> P;

bool adj[N][N];
bool up[N][N];//up[i][j] = 1 i >=j 
bool cpyadj[N][N];
bool cpyup[N][N];

class Polygon{
public:
  vector<P> ori,newp;
  int oriid,newid;
  int cutbit;
  vector<P> inipos;
};

void outputpolygon(vector<P> &a){
  cout << "[";
  rep(i,a.size()+1)cout << a[(i+1)%a.size()]<<",";
  cout << "],"<<endl;
}


#define RIGHT 1
#define LEFT -1

double cross(P a,P b){
  return a.real()*b.imag()-a.imag()*b.real();
}

double dot(P a,P b){
  return a.real()*b.real()+a.imag()*b.imag();
}

bool isp(P &a,P &b,P &c){
  return abs(a-c)+abs(b-c) < abs(a-b) + eps;
}

P intersection_ll(P &a1,P &a2,P &b1,P &b2){
  P a=a2-a1,b=b2-b1;
  return a1+ a*cross(b,b1-a1)/cross(b,a);
}

int ccw(P a,P b){
  if (cross(a,b)    < -0)return RIGHT;
  else if(cross(a,b)>  0)return LEFT;
  return 2;
}

bool is_intersected_ls(P &a1,P &a2,P &b1,P &b2){
  if (isp(a1,a2,b1)||isp(a1,a2,b2)||isp(b1,b2,a1)||
      isp(b1,b2,a2))return true;
  if (cross(a2-a1,b1-a1)*cross(a2-a1,b2-a1)<-eps &&
      cross(b2-b1,a1-b1)*cross(b2-b1,a2-b1)<-eps)
    return true;
  return false;
}

//LEFT remain,RIGHT reflect
void Convex_cut(vector<P> in,P &a1,P &a2,
		vector<P> &ori,vector<P> &newp){
  int n = in.size();
  ori.clear();newp.clear();
  rep(i,n){
    P now = in[i],next=in[(i+1)%n];
    if( ccw(a1-a2,now-a2) == LEFT)ori.pb(now);
    else if( ccw(a1-a2,now-a2) == RIGHT)newp.pb(now);
    if (ccw(a1-a2,now-a2)*ccw(a1-a2,next-a2)<0){
      ori.pb(intersection_ll(a1,a2,now,next));
      newp.pb(intersection_ll(a1,a2,now,next));
    }
  }
}

pair<P,P> make_line(P p,P q){
  int cutpos=RIGHT;
  P tmp=(p+q);
  tmp.real()/=2;tmp.imag()/=2;
  P ret=q-tmp;
  swap(ret.real(),ret.imag());
  ret.real()*=-1;
  if ( ccw(ret,p-tmp) != cutpos)return make_pair(tmp,ret+tmp);
  return make_pair(ret+tmp,tmp);
}

bool is_in(vector<P> &in,P &a){
  int cnt=0;
  int n = in.size();
  rep(i,n){
    P cur = in[i]-a,next=in[(i+1)%n]-a;
    if (cur.imag()>next.imag())swap(cur,next);
    if (cur.imag()<0&&0<=next.imag()&&
	cross(next,cur)>= 0)cnt++;
    if (isp(in[i],in[(i+1)%n],a))return true;
  }

  if (cnt%2 == 1)return true;
  return false;
}

P reflect(P &o,P &p,P &q){
  P N=p-o,L=q-o;
  double t = abs(L);
  N/=abs(N);
  L/=abs(L);
  double prepL = dot(N,L);//theta element of vector L against N (|L|=|N|=1
  double d=2*prepL;
  P r(d*N - L);//R vector symmetric point of L
  return o+t*r;
}

int find_most_upper(int n,Polygon *in,P &p){
  int index = -1;
  rep(i,n){
    if (is_in(in[i].ori,p)){
      if (index == -1)index =i;
      else if (up[i][index])index=i;
    }
  }
  return index;
}

//a ori,b newp
bool is_intersected_polygon(vector<P> &a,vector<P> &b){
  rep(i,a.size()){
    if (is_in(b,a[i]))return true;
    rep(j,b.size()){
      if (is_intersected_ls(a[i],a[(i+1)%a.size()],
			    b[j],b[(j+1)%b.size()])){
	return true;
      }
    }
  }
  rep(j,b.size())if (is_in(a,b[j]))return true;
  return false;
}


double distance_l_p(P a,P b,P c){
  return abs( cross(b-a,c-a))/abs(b-a);
}

bool issame(P &a,P &b){
  return fabs(a.real()-b.real())<eps && fabs(a.imag()-b.imag())<eps;
}

bool have_same_line(vector<P> &in1,vector<P> &in2,P &a,P &b,bool flag){
  rep(i,in1.size()){
    rep(j,in2.size()){
      if (isp(in1[i],in1[(i+1)%in1.size()],in2[j])
	  ||isp(in1[i],in1[(i+1)%in1.size()],in2[(j+1)%in2.size()])
	  //||isp(in2[j],in2[(j+1)%in2.size()],in1[i])||
	  //	  ||isp(in2[j],in2[(j+1)%in2.size()],in1[(i+1)%in1.size()])
	  )return true;

      if ((issame(in1[i],in2[j])&&issame(in1[(i+1)%in1.size()],in2[(j+1)%in2.size()]))
	||
	(issame(in1[i],in2[(j+1)%in2.size()])&&issame(in1[(i+1)%in1.size()],in2[j]))
	)return true;
    }
  }
  return false;
}

bool vis[N];
void origami(int &n,int ini,Polygon in[N],P &a,P &b,
	     pair<P,P> *line,int querry){
  int m = n;
  vector<P> dummy;
  rep(i,N){
    in[i].newp.clear(),in[i].newid=-1;//nen no tame
  }

  rep(i,N)vis[i]=false;
  queue<int> Q;
  Q.push(ini);
  while(!Q.empty()){
    int now = Q.front();Q.pop();
    if (vis[now])continue;
    
    vis[now]=true;

    Convex_cut(in[now].ori,a,b,in[now].ori,in[now].newp);
    if (in[now].newp.size() != 0){
      in[now].oriid=now;
      in[now].newid=m++;
      in[in[now].newid].cutbit=in[now].cutbit|(1<<querry);
    }
    
    
    //    in[now].inipos.clear();
    in[now].inipos=in[now].newp;
    for(int j=querry-1;j>=0;j--){
      if((in[now].cutbit&(1<<j)) != 0){
	rep(k,in[now].inipos.size()){
	  in[now].inipos[k]=reflect(line[j].first,line[j].second,in[now].inipos[k]);
	}
      }
    }
    
    
    rep(i,n){
      if (i == now)continue;
      if (adj[now][i]){
	if(have_same_line(in[now].inipos,in[i].inipos,a,b,false))
	  Q.push(i);
      }
      if (up[i][now]){
	if (is_intersected_polygon(in[now].newp,in[i].ori))
	  Q.push(i);
      }
    }
  }
  
  rep(i,n){
    rep(j,in[i].newp.size()){
      in[i].newp[j]=reflect(a,b,in[i].newp[j]);
    }
  }
  

  rep(i,n){
    int myori=in[i].oriid,mynew=in[i].newid;
    if (in[i].newp.size() == 0)mynew=-1;
    
    if (mynew != -1){
      up[myori][mynew]=false;
      up[mynew][myori]=true;
    }
    
    rep(j,n){
      if (i == j)continue;
      int yourori=in[j].oriid,yournew=in[j].newid;
      bool tmp = up[i][j];
      //in[i].ori-in[j].ori
      up[myori][yourori]=up[myori][yourori];

      //in[i].ori-in[j].newp
      if (yournew != -1){
	up[myori][yournew]=false;
      }

      //in[i].newp-in[j].ori
      if (mynew != -1){
	if (is_intersected_polygon(in[i].newp,in[j].ori)){
	  up[mynew][yourori]=true;
	}else {
	  up[mynew][yourori]=false;
	}
      }
 
      //in[i].newp-in[j].ori
      if (mynew != -1 && yournew != -1){
	if (up[yourori][myori] && is_intersected_polygon(in[i].newp,in[j].newp))
	  up[mynew][yournew]=true;
	else up[mynew][yournew]=false;
      }
    }
  }
        
    
    
  rep(i,n){
    if (in[i].newp.size() != 0){
      in[in[i].newid].ori=in[i].newp;
      in[in[i].newid].oriid=in[i].newid;
      in[i].newp.clear();
    }
  }

  n = m;

  //  cout << m << endl;
  rep(i,m){
    in[i].inipos.clear();
    in[i].inipos=in[i].ori;
    for(int j=querry;j>=0;j--){
      if((in[i].cutbit&(1<<j)) != 0){
	rep(k,in[i].inipos.size()){
	  in[i].inipos[k]=reflect(line[j].first,line[j].second,in[i].inipos[k]);
	}
      }
    }
  }

  rep(i,m){
    REP(j,i+1,m){
      if (have_same_line(in[i].inipos,in[j].inipos,a,b,true)){
	adj[i][j]=adj[j][i]=true;
      }else adj[i][j]=adj[j][i]=false;
    }
  }
}
	     
int solve(int querry){
  int n=1;
  static Polygon in[N];
  pair<P,P> line[10];
  P pos[10];
  // initialization
  rep(i,N){
    in[i].ori.clear();
    in[i].newp.clear();
    in[i].inipos.clear();
    in[i].oriid=i;
    in[i].newid=-1;
    in[i].cutbit=0;
  }
  rep(i,N)rep(j,N)adj[i][j]=false,up[i][j]=false;
  
  in[0].ori.pb(P(0,0));
  in[0].ori.pb(P(0,100));
  in[0].ori.pb(P(100,100));
  in[0].ori.pb(P(100,0));
  in[0].inipos=in[0].ori;

  rep(i,querry){
    P p,q;
    cin>>p.real()>>p.imag()>>q.real()>>q.imag();
    pos[i]=p;
    pair<P,P> tmp;
    line[i] = make_line(p,q);
  }

  rep(i,querry){
    int index = find_most_upper(n,in,pos[i]);
    if (index == -1){
    }else origami(n,index,in,line[i].first,line[i].second,
		  line,i);
  }

  
  int cnt=0;
  P hole;
  cin>>hole.real()>>hole.imag();
  rep(i,n){
    if (in[i].ori.size() && is_in(in[i].ori,hole))cnt++;
  }

  return cnt;
}

main(){
  int q;
  while(cin>>q&&q){
    cout << solve(q) << endl; 
  }
}




void output(int n,Polygon in[N]){
  cout <<"output begin" << endl;
  rep(i,n){
    if (in[i].ori.size() == 0)continue;
    outputpolygon(in[i].ori);
	
    //outputpolygon(in[i].inipos);
    //    else cout <<"error " << i << endl;//outputpolygon(in[i].ori);
  }
  cout << endl;

  cout << "up"<<endl;
  rep(i,n){
    rep(j,n)cout << up[i][j];
    cout << endl;
  }
  cout << endl;
  
  
  cout << "adj " << endl;
  rep(i,n){
    rep(j,n)cout << adj[i][j];
    cout <<endl;
  }
  cout << endl;
  

  cout <<"output end" << endl<<endl;
}
accuracy: 1
time_ms: 4930
memory_kb: 9584
final_rank: 6