Problem:
Problem D:
Digits on the Floor
Taro attempts to tell digits to Hanako by putting straight bars on the floor. Taro wants to
express each digit by making one of the forms shown in Figure 1.
Since Taro may not have bars of desired lengths, Taro cannot always make forms exactly as
shown in Figure 1. Fortunately, Hanako can recognize a form as a digit if the connection
relation between bars in the form is kept. Neither the lengths of bars nor the directions of forms
affect Hanako’s perception as long as the connection relation remains the same. For example,
Hanako can recognize all the awkward forms in Figure 2 as digits. On the other hand, Hanako
cannot recognize the forms in Figure 3 as digits. For clarity, touching bars are slightly separated
in Figures 1, 2 and 3. Actually, touching bars overlap exactly at one single point.
Figure 1: Representation of digits
Figure 2: Examples of forms recognized as digits
In the forms, when a bar touches another, the touching point is an end of at least one of them.
That is, bars never cross. In addition, the angle of such two bars is always a right angle.
To enable Taro to represent forms with his limited set of bars, positions and lengths of bars can
be changed as far as the connection relations are kept. Also, forms can be rotated.
Keeping the connection relations means the following.
Figure 3: Forms not recognized as digits (these kinds of forms are not contained in the dataset)
Separated bars are not made to touch.
Touching bars are not made separate.
When one end of a bar touches another bar, that end still touches the same bar. When it
touches a midpoint of the other bar, it remains to touch a midpoint of the same bar on
the same side.
The angle of touching two bars is kept to be the same right angle (90 degrees and -90
degrees are considered different, and forms for 2 and 5 are kept distinguished).
Your task is to find how many times each digit appears on the floor.
The forms of some digits always contain the forms of other digits. For example, a form for
9 always contains four forms for 1, one form for 4, and two overlapping forms for 7. In this
problem, ignore the forms contained in another form and count only the digit of the “largest”
form composed of all mutually connecting bars. If there is one form for 9, it should be interpreted
as one appearance of 9 and no appearance of 1, 4, or 7.
Input
The input consists of a number of datasets. Each dataset is formatted as follows.
n
x
1a
y
1a
x
1b
y
1b
x
2a
y
2a
x
2b
y
2b
.
.
.
x
na
y
na
x
nb
y
nb
In the first line,
n
represents the number of bars in the dataset. For the rest of the lines, one
line represents one bar. Four integers
x
a
,
y
a
,
x
b
,
y
b
, delimited by single spaces, are given in
each line.
x
a
and
y
a
are the
x-
and
y-
coordinates of one end of the bar, respectively.
x
b
and
y
b
are those of the other end. The coordinate system is as shown in Figure 4. You can assume
1 ≤
n
≤ 1000 and 0 ≤
x
a
,
y
a
,
x
b
,
y
b
≤ 1000.
The end of the input is 
...(truncated)

Submitted solutions:

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int n, xa[10010], xb[10010], ya[10010], yb[10010], v[1010][1010], xx1, xx2, q1[10010];
int q[10010], qq[10010], r, ll, rr, in[10010], v1[10010], ans[100], c1, c2, c3;
struct arr{
	int x, y;
}x1, x2, x3, u;
int main()
{
	while (1)
	{
		memset(v, 0, sizeof(v));
		memset(v1, 0, sizeof(v1));
		memset(ans, 0, sizeof(ans));
		scanf("%d", &n);
		if (!n) break;
		r = 0;
		for (int i = 1; i <= n; i++)
		{
			scanf("%d%d%d%d", &xa[i], &ya[i], &xb[i], &yb[i]);
			if (!v[xa[i]][ya[i]]) q[++r] = xa[i] * 10000 + ya[i], v[xa[i]][ya[i]] = r;
			if (!v[xb[i]][yb[i]]) q[++r] = xb[i] * 10000 + yb[i], v[xb[i]][yb[i]] = r;
		}
		for (int ii = 1; ii <= r; ii++)
		if (!v1[ii])
		{
			ll = rr = 0;
			q1[0] = 0;
			c1 = c2 = c3 = 0;
			qq[++rr] = ii, v1[ii] = 1;
			while (ll < rr)
			{
				u.x = q[qq[++ll]] / 10000, u.y = q[qq[ll]] % 10000;
				in[ll] = 0;
				for (int j = 1; j <= n; j++)
				{
					if ((xa[j] - u.x) * (xb[j] - u.x) <= 0 && (ya[j] - u.y) * (yb[j] - u.y) <= 0 &&
					(xa[j] - u.x) * (yb[j] - u.y) == (xb[j] - u.x) * (ya[j] - u.y))
					{
						if (xb[j] != u.x || yb[j] != u.y)
						{
							in[ll]++;
							if (!v1[v[xb[j]][yb[j]]])
								qq[++rr] = v[xb[j]][yb[j]], v1[v[xb[j]][yb[j]]] = 1;
						}
						if (xa[j] != u.x || ya[j] != u.y)
						{
							in[ll]++;
							if (!v1[v[xa[j]][ya[j]]])
								qq[++rr] = v[xa[j]][ya[j]], v1[v[xa[j]][ya[j]]] = 1;
						}
						q1[++q1[0]] = j;
					}
				}
				if (in[ll] == 1) c1++;
				if (in[ll] == 2) c2++;
				if (in[ll] == 3) c3++;
			}
			
			for (int j = 1; j <= q1[0]; j++)
				for (int k = 1; k <= r; k++)
					if (!v1[k])
					{
						u.x = q[k] / 10000, u.y = q[k] % 10000;
						if ((xa[q1[j]] - u.x) * (xb[q1[j]] - u.x) <= 0 && (ya[q1[j]] - u.y) * (yb[q1[j]] - u.y) <= 0 &&
						(xa[q1[j]] - u.x) * (yb[q1[j]] - u.y) == (xb[q1[j]] - u.x) * (ya[q1[j]] - u.y))
							qq[++rr] = k, v1[k] = 1;
					}
			
			while (ll < rr)
			{
				u.x = q[qq[++ll]] / 10000, u.y = q[qq[ll]] % 10000;
				in[ll] = 0;
				for (int j = 1; j <= n; j++)
				{
					if ((xa[j] - u.x) * (xb[j] - u.x) <= 0 && (ya[j] - u.y) * (yb[j] - u.y) <= 0 &&
					(xa[j] - u.x) * (yb[j] - u.y) == (xb[j] - u.x) * (ya[j] - u.y))
					{
						if (xb[j] != u.x || yb[j] != u.y)
						{
							in[ll]++;
							if (!v1[v[xb[j]][yb[j]]])
							{
								qq[++rr] = v[xb[j]][yb[j]], v1[v[xb[j]][yb[j]]] = 1;
							}
						}
						if (xa[j] != u.x || ya[j] != u.y)
						{
							in[ll]++;
							if (!v1[v[xa[j]][ya[j]]]) qq[++rr] = v[xa[j]][ya[j]], v1[v[xa[j]][ya[j]]] = 1;
						}
					}
				}
				if (in[ll] == 1) c1++;
				if (in[ll] == 2) c2++;
				if (in[ll] == 3) c3++;
			}
			if (c1 == 0 && c2 == 4 && c3 == 0) ans[0]++;
			if (c1 == 2 && c2 == 0 && c3 == 0) ans[1]++;
			if (c1 == 3 && c2 == 2 && c3 == 1) ans[3]++;
			if (c1 == 3 && c2 == 1 && c3 == 1) ans[4]++;
			if (c1 == 1 && c2 == 4 && c3 == 1) ans[6]++;
			if (c1 == 2 && c2 == 2 && c3 == 0) ans[7]++;
			if (c1 == 0 && c2 == 4 && c3 == 2) ans[8]++;
			if (c1 == 1 && c2 == 3 && c3 == 1) ans[9]++;
			if (c1 == 2 && c2 == 4 && c3 == 0)
			{
				for (int i = 1; i <= rr; i++)
				if (in[i] == 1)
				{
					x1.x = q[qq[i]] / 10000, x1.y = q[qq[i]] % 10000;
					xx1 = qq[i];
					break;
				}
				for (int i = 1; i <= n; i++)
				{
					if (v[xa[i]][ya[i]] == xx1)
					{
						x2.x = xb[i], x2.y = yb[i];
						break;
					}
					if (v[xb[i]][yb[i]] == xx1)
					{
						x2.x = xa[i], x2.y = ya[i];
						break;
					}
				}
				xx2 = v[x2.x][x2.y];
				for (int i = 1; i <= n; i++)
				{
					if (v[xa[i]][ya[i]] == xx2 && v[xb[i]][yb[i]] != xx1)
					{
						x3.x = xb[i], x3.y = yb[i];
						break;
					}
					if (v[xa[i]][ya[i]] != xx1 && v[xb[i]][yb[i]] == xx2)
					{
						x3.x = xa[i], x3.y = ya[i];
						break;
					}
				}
				if ((x2.x - x1.x) * (x3.y - x1.y) - (x3.x - x1.x) * (x2.y - x1.y) > 0) ans[5]++;
				else ans[2]++;
			}
		}
		for (int i = 0; i < 9; i++) printf("%d ", ans[i]);
		printf("%d\n", ans[9]);
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 7072
final_rank: 18

code_snippet: #include <map>
#include <vector>
#include <iostream>
#include <deque>
#include <algorithm>

using namespace std;

map<vector<int>, int> signature;

int vec(pair<int, int> a, pair<int, int> b) {
    return a.first * b.second - b.first * a.second;
}

pair<int, int> operator - (pair<int, int> a, pair<int, int> b) {
    return pair<int, int>(a.first - b.first, a.second - b.second);
}

bool isInTheMidOf(pair<int, int> start, pair<int, int> end, pair<int, int> point) {
    if (point == start || point == end) return false;
    end = end - start;
    point = point - start;
    start = start - start;
    if (end.first >= 0 && !(point.first >= 0 && point.first <= end.first)) return false;
    if (end.first < 0 && !(point.first < 0 && point.first >= end.first)) return false;
    if (end.second >= 0 && !(point.second >= 0 && point.second <= end.second)) return false;
    if (end.second < 0 && !(point.second < 0 && point.second >= end.second)) return false;
    return vec(end, point) == 0;
}

bool is2(pair<int, int> start, pair<int, int> end, pair<int, int> point) {
    end = end - start;
    point = point - start;
    start = start - start;
    return vec(end, point) < 0;
}

vector<vector<int> > g;
vector<bool> used;
deque<int> found;

void dfs(int v) {
    found.push_back(v);
    used[v] = true;
    for (int i = 0; i < g[v].size(); ++i) {
        int to = g[v][i];
        if (used[to]) continue;
        dfs(to);
    }
}

int main() {
    static const int tmp0[] = {2, 2, 2, 2};
    vector<int> _sig0 (tmp0, tmp0 + sizeof(tmp0) / sizeof(tmp0[0]));
    static const int tmp1[] = {1, 1};
    vector<int> _sig1 (tmp1, tmp1 + sizeof(tmp1) / sizeof(tmp1[0]));
    static const int tmp3[] = {1, 1, 1, 2, 2, 3};
    vector<int> _sig3 (tmp3, tmp3 + sizeof(tmp3) / sizeof(tmp3[0]));
    static const int tmp4[] = {1, 1, 1, 2, 3};
    vector<int> _sig4 (tmp4, tmp4 + sizeof(tmp4) / sizeof(tmp4[0]));
    static const int tmp6[] = {1, 2, 2, 2, 2, 3};
    vector<int> _sig6 (tmp6, tmp6 + sizeof(tmp6) / sizeof(tmp6[0]));
    static const int tmp7[] = {1, 1, 2, 2};
    vector<int> _sig7 (tmp7, tmp7 + sizeof(tmp7) / sizeof(tmp7[0]));
    static const int tmp8[] = {2, 2, 2, 2, 3, 3};
    vector<int> _sig8 (tmp8, tmp8 + sizeof(tmp8) / sizeof(tmp8[0]));
    static const int tmp9[] = {1, 2, 2, 2, 3};
    vector<int> _sig9 (tmp9, tmp9 + sizeof(tmp9) / sizeof(tmp9[0]));
    signature[_sig0] = 0;
    signature[_sig1] = 1;
    signature[_sig3] = 3;
    signature[_sig4] = 4;
    signature[_sig6] = 6;
    signature[_sig7] = 7;
    signature[_sig8] = 8;
    signature[_sig9] = 9;
    int n;
    while (cin >> n) {
        if (n == 0) break;
        vector<pair<pair<int, int>, pair<int, int> > > segments(n);
        for (int i = 0; i < n; ++i) {
            pair<pair<int, int>, pair<int, int> >& e = segments[i];
            cin >> e.first.first >> e.first.second >> e.second.first >> e.second.second;
        }
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                if (i == j) continue;
                if (isInTheMidOf(segments[i].first, segments[i].second, segments[j].first)) {
                    segments.push_back(make_pair(segments[j].first, segments[i].second));
                    segments[i].second = segments[j].first;
                }
                if (isInTheMidOf(segments[i].first, segments[i].second, segments[j].second)) {
                    segments.push_back(make_pair(segments[j].second, segments[i].second));
                    segments[i].second = segments[j].second;
                }
            }
        }
        vector<pair<int, int> > points(2*segments.size());
        for (int i = 0; i < segments.size(); ++i) {
            points[i*2] = segments[i].first;
            points[i*2+1] = segments[i].second;
        }
        sort(points.begin(), points.end());
        points.resize(unique(points.begin(), points.end()) - points.begin());
        g.assign(points.size(), vector<int>());
        for (int i = 0; i < segments.size(); ++i) {
            pair<int, int>& st = segments[i].first;
            pair<int, int>& en = segments[i].second;
            int a = int(lower_bound(points.begin(), points.end(), st) - points.begin());
            int b = int(lower_bound(points.begin(), points.end(), en) - points.begin());
            g[a].push_back(b);
            g[b].push_back(a);
        }
        used.assign(points.size(), false);
        vector<int> answer(10, 0);
        for (int i = 0; i < points.size(); ++i) {
            if (!used[i]) {
                dfs(i);
                vector<int> power;
                for (int j = 0; j < found.size(); ++j) {
                    int& e = found[j];
                    power.push_back(int(g[e].size()));
                }
                sort(power.begin(), power.end());
                static const int tmp[] = {1, 1, 2, 2, 2, 2};
                vector<int> _2or5 (tmp, tmp + sizeof(tmp) / sizeof(tmp[0]));
                if (power == _2or5) {
                    int edge = -1, second = -1, third = -1;
                    for (int j = 0; j < found.size(); ++j) {
                        int& e = found[j];
                        if (g[e].size() == 1) edge = e;
                    }
                    second = g[edge].front();
                    third = g[second].front() == edge ? g[second].back() : g[second].front();
                    if (is2(points[edge], points[second], points[third])) {
                        answer[2]++;
                    } else {
                        answer[5]++;
                    }
                } else {
                    answer[signature[power]]++;
                }
                found.clear();
            }
        }
        for (int i = 0; i < 9; ++i) cout << answer[i] << ' ';
        cout << answer.back() << '\n';
    }
}
accuracy: 1
time_ms: 40
memory_kb: 3252
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;

const int N=1000;
const int M=30;

struct Point { int x,y; };
struct Line { Point p,q; };

int operator==(const Point &p, const Point &q) {
    return p.x==q.x && p.y==q.y;
}

int cross(const Point &a, const Point &b, const Point &c) {
    return (a.x-b.x)*(c.y-b.y)-(c.x-b.x)*(a.y-b.y);
}

int cut(const Line &l, const Point &a) {
    return (l.p.x-a.x)*(a.y-l.q.y)==(l.p.y-a.y)*(a.x-l.q.x) &&
            ((l.p.x-a.x)*(l.q.x-a.x)<0 || (l.p.y-a.y)*(l.q.y-a.y)<0);
}

int touch(const Line &a, const Line &b) {
    return a.p==b.p || a.p==b.q || a.q==b.p || a.q==b.q ||
            cut(a,b.p) || cut(a,b.q) || cut(b,a.p) || cut(b,a.q);
}


int n,used[N],cnt[10];
Line line[N];
int m,g[M][M],d[M];
Point p[M];

int addp(Point pt) {
    int i=0;
    while (i<m && !(p[i]==pt)) i++;
    if (i==m) p[m++]=pt;
    return i;
}

int recognize() {
    // split the lines
    for (int k=0; k<m; k++)
        for (int i=0; i<m; i++)
            for (int j=0; j<m; j++)
                if (i!=j && i!=k && j!=k && g[i][j]) {
                    Line l = {p[i],p[j]};
                    if (cut(l,p[k])) {
                        g[i][j]=g[j][i]=0;
                        g[i][k]=g[k][i]=g[j][k]=g[k][j]=1;
                    }
                }

    int s=0;
    memset(d,0,sizeof(d));
    for (int i=0; i<m; i++)
        for (int j=0; j<m; j++)
            s+=g[i][j],d[i]+=g[i][j];
    s/=2;

    // recognize the number by features:
    //          n   0 1 2 3 4 5 6 7 8 9
    //   #point m   4 2 6 6 5 6 6 4 6 5
    //   #line  s   4 1 5 5 4 5 6 3 7 5
    if (m==4 && s==4) return 0;
    if (m==2 && s==1) return 1;
    if (m==5 && s==4) return 4;
    if (m==6 && s==6) return 6;
    if (m==4 && s==3) return 7;
    if (m==6 && s==7) return 8;
    if (m==5 && s==5) return 9;

    // 3 has a point that connects three lines.
    for (int i=0; i<m; i++)
        if (d[i]==3) return 3;

    // check 2 and 5 by line angle.
    for (int i=0; i<m; i++)
        if (d[i]==1) {
            int j=0, k=0;
            while (!g[i][j]) j++;
            while (!g[j][k] || k==i) k++;
            if (cross(p[i],p[j],p[k])>0) return 2; else return 5;
        }

    // error
    return 0;
}

int solve() {
    cin>>n;
    if (n==0) return 0;
    for (int i=0; i<n; i++)
        cin>>line[i].p.x>>line[i].p.y>>line[i].q.x>>line[i].q.y;


    memset(cnt,0,sizeof(cnt));
    memset(used,0,sizeof(used));
    for (int i=0; i<n; i++)
        if (!used[i]) {
            // BFS: find connected lines
            int cn=0;
            Line c[M];
            c[cn++]=line[i]; used[i]=1;
            for (int k=0; k<cn; k++)
                for (int j=i+1; j<n; j++)
                    if (!used[j] && touch(c[k],line[j])) {
                        c[cn++]=line[j]; used[j]=1;
                    }

            // construct graph and recognize it
            m=0;
            memset(g,0,sizeof(g));
            for (int k=0; k<cn; k++) {
                int a=addp(c[k].p), b=addp(c[k].q);
                g[a][b]=g[b][a]=1;
            }
            cnt[recognize()]++;
        }

    for (int i=0; i<=9; i++)
        cout<<cnt[i]<<(i<9 ? ' ' : '\n');
    return 1;
}

int main() {
    while (solve());
    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3108
final_rank: 2

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"
#include "complex"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-12;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

class UnionFind {
	vector<int>parent;
	vector<int>rank;
public:
	UnionFind(int num) {
		num++;
		parent.resize(num);
		rank.resize(num);
		for (int i = 0; i < num; i++) {
			parent[i] = i;
			rank[i] = 0;
		}
	}
	int Find(int node) {
		if (parent[node] == node)return node;
		else return parent[node] = Find(parent[node]);
	}
	void Unite(int u, int v) {
		u = Find(u);
		v = Find(v);
		if (u == v)return;
		if (rank[u] < rank[v])parent[u] = v;
		else {
			parent[v] = u;
			if (rank[u] == rank[v])rank[u]++;
		}
	}
	bool Check_Same(int u, int v) {
		return Find(u) == Find(v);
	}
};

struct  Point {
	long double x;
	long double y;
	Point(long double xx, long double yy) {
		x = xx, y = yy;
	}
	Point() {
	}
	Point operator + (const Point& c)const {
		Point box;
		box.x = x + c.x;
		box.y = y + c.y;
		return box;
	}
	bool operator == (const Point& c)const {
		return x == c.x&&y == c.y;
	}
	Point operator - (const Point& c)const {
		Point box;
		box.x = x - c.x;
		box.y = y - c.y;
		return box;
	}
	Point operator * (const long double& b)const {
		Point box;
		box.x = x * b;
		box.y = y * b;
		return box;
	}
	bool operator <(const Point& c)const {
		if (y < c.y)return true;
		if (y > c.y)return false;
		if (x < c.x)return true;
		return false;
	}
	bool operator >(const Point& c)const {
		if (y > c.y)return true;
		if (y < c.y)return false;
		if (x > c.x)return true;
		return false;
	}
	long double det(Point a) {
		return x * a.y - y * a.x;
	}
};

struct Line {
	long double a, b, c;
	Line(const int aa, const int bb, const int cc) {
		a = aa, b = bb, c = cc;
	}
	Line(const Point s, const Point t) {
		if (abs(s.x - t.x) < EPS) {
			a = 1;
			b = 0;
		}
		else {
			b = 1;
			a = (t.y - s.y) / (s.x - t.x);
		}
		c = s.x*a + s.y*b;
	}
};

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

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

long double Distance(Point a, Point b) {
	return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}

long double Distance(Point a, pair<Point, Point>b) {
	Line l = Line(b.first, b.second);
	if (abs(l.a*a.x + l.b*a.y - l.c) < EPS) {
		if (abs(Distance(a, b.first) + Distance(a, b.second) - Distance(b.second, b.first)) <= sqrt(EPS))return 0;
		return min(Distance(a, b.first), Distance(a, b.second));
	}
	long double A = pow((b.first.x - b.second.x), 2) + pow((b.first.y - b.second.y), 2);
	long double B = 2 * (a.x - b.first.x)*(b.first.x - b.second.x) + 2 * (a.y - b.first.y)*(b.first.y - b.second.y);
	long double r = B / 2 / A;
	r = -r;
	if (r >= 0 && r <= 1) {
		return Distance(a, Point(b.first.x + r * (b.second.x - b.first.x), b.first.y + r * (b.second.y - b.first.y)));
	}
	else {
		return min(Distance(a, b.first), Distance(a, b.second));
	}
}

bool LineCross(Point a1, Point a2, Point b1, Point b2) {
	return cross(a2 - a1, b1 - a1)*cross(a2 - a1, b2 - a1) < EPS&&cross(b2 - b1, a1 - b1)*cross(b2 - b1, a2 - b1) < EPS && !(abs((a1 - a2).x*(a1 - b1).y - (a1 - a2).y*(a1 - b1).x)<EPS && abs((a1 - a2).x*(a1 - b2).y - (a1 - a2).y*(a1 - b2).x)<EPS&&abs(Distance(a1, a2) - Distance(a1, b1) - Distance(a2, b1)) > EPS&&abs(Distance(a1, a2) - Distance(a2, b2) - Distance(a1, b2)) > EPS&&abs(Distance(b1, b2) - Distance(a1, b1) - Distance(a1, b2)) > EPS&&abs(Distance(b1, b2) - Distance(a2, b1) - Distance(a2, b2)) > EPS);
}

long double Distance(pair<Point, Point>a, pair<Point, Point>b) {
	if (LineCross(a.first, a.second, b.first, b.second))return 0;
	return min({ Distance(a.first,b),Distance(a.second,b),Distance(b.first,a),Distance(b.second,a) });
}

Point LineCross(Line a, Line b) {
	Point ret;
	ret.x = (a.c*b.b - a.b*b.c) / (a.a*b.b - a.b*b.a);
	ret.y = -(a.c*b.a - a.a*b.c) / (a.a*b.b - a.b*b.a);
	return ret;
}

long double TriangleArea(Point a, Point b, Point c) {
	long double A, B, C;
	A = Distance(a, b);
	B = Distance(a, c);
	C = Distance(b, c);
	long double S = (A + B + C) / 2;
	return sqrt(S*(S - A)*(S - B)*(S - C));
}

bool IsPointLeft(pair<Point, Point>a, Point b) {
	a.second = a.second - a.first;
	b = b - a.first;
	a.first = a.first - a.first;
	long double radline = atan2(a.second.y, a.second.x);
	long double radpoint = atan2(b.y, b.x) - radline;
	if (sin(radpoint) >= -EPS)return true;
	else return false;
}

bool IsPointInPolygon(Point p, vector<Point>poly) {
	bool ret = true;
	for (int i = 0; i < poly.size(); i++) {
		if (Distance(p, { poly[i],poly[(i + 1) % poly.size()] }) <= EPS) return true;
		ret &= IsPointLeft({ poly[i],poly[(i + 1) % poly.size()] }, p);
	}
	return ret;
}

long double Area(vector<Point>p) {
	long double ret = 0;
	for (int i = 2; i < p.size(); i++) {
		ret += TriangleArea(p[0], p[i - 1], p[i]);
	}
	return ret;
}

vector<vector<Point>>DividePolygonByLine(vector<Point>p, pair<Point, Point>l) {
	vector<int>cr;
	vector<Point>cp;
	for (int k = 0; k < p.size(); k++) {
		int nx = k + 1;
		nx %= p.size();
		if (LineCross(p[k], p[(k + 1) % p.size()], l.first, l.second)) {
			auto np = LineCross(Line(p[k], p[(k + 1) % p.size()]), Line(l.first, l.second));
			bool flag = true;
			for (auto l : cp) {
				if (Distance(l, np) <= EPS)flag = false;
			}
			if (flag) {
				cr.push_back(k);
				cp.push_back(np);
			}
		}
	}
	vector<Point>w;
	vector<Point>x;
	if (cr.size() != 2)return vector<vector<Point>>(1, p);
	int cnt = cr[0];
	do {
		if (w.empty() || Distance(w.back(), p[cnt]) > EPS)w.push_back(p[cnt]);
		if (cnt == cr[0]) {
			if (w.empty() || Distance(w.back(), cp[0]) > EPS)w.push_back(cp[0]);
			if (w.empty() || Distance(w.back(), cp[1]) > EPS)w.push_back(cp[1]);
			cnt = cr[1] + 1;
			cnt %= p.size();
		}
		else if (cnt == cr[1]) {
			if (w.empty() || Distance(w.back(), cp[1]) > EPS)w.push_back(cp[1]);
			if (w.empty() || Distance(w.back(), cp[0]) > EPS)w.push_back(cp[0]);
			cnt = cr[0] + 1;
			cnt %= p.size();
		}
		else {
			cnt++;
			cnt %= p.size();
		}
	} while (cnt != cr[0]);
	cnt = cr[1];
	do {
		if (x.empty() || Distance(x.back(), p[cnt]) > EPS)x.push_back(p[cnt]);
		if (cnt == cr[0]) {
			if (x.empty() || Distance(x.back(), cp[0]) > EPS)x.push_back(cp[0]);
			if (x.empty() || Distance(x.back(), cp[1]) > EPS)x.push_back(cp[1]);
			cnt = cr[1] + 1;
			cnt %= p.size();
		}
		else if (cnt == cr[1]) {
			if (x.empty() || Distance(x.back(), cp[1]) > EPS)x.push_back(cp[1]);
			if (x.empty() || Distance(x.back(), cp[0]) > EPS)x.push_back(cp[0]);
			cnt = cr[0] + 1;
			cnt %= p.size();
		}
		else {
			cnt++;
			cnt %= p.size();
		}
	} while (cnt != cr[1]);
	vector<vector<Point>>ret;
	ret.push_back(w);
	ret.push_back(x);
	return ret;
}

struct Circle {
	long double x, y, r;
	void Input() {
		cin >> x >> y >> r;
	}
	bool operator==(const Circle&c)const {
		return x == c.x&&y == c.y&&r == c.r;
	}
};

vector<Point>CircleCross(Circle a, Circle b) {
	vector<Point>ret;
	Point ap(a.x, a.y);
	Point bp(b.x, b.y);
	Point dp = bp - ap;
	auto dis = Distance(ap, bp);
	if (a == b)return ret;
	if (a.r + b.r < Distance(ap, bp))return ret;
	if (abs(a.r + b.r - dis) <= EPS) {
		ret.push_back(ap + dp * (a.r / (a.r + b.r)));
		return ret;
	}
	if (abs(abs(a.r - b.r) - dis) <= EPS) {
		ret.push_back(ap + dp * (a.r / (a.r - b.r)));
	}
	long double ad;
	ad = (a.r*a.r - b.r*b.r + dis * dis) / 2 / dis;
	Point cp = ap + dp * (ad / dis);
	long double amari = sqrt(a.r*a.r - ad * ad);
	ret.push_back(cp + Point(-dp.y, dp.x)*(amari / dis));
	ret.push_back(cp - Point(-dp.y, dp.x)*(amari / dis));
	return ret;
}

vector<pair<Point, Point>>Common_Tangent(Circle a, Circle b, long double inf) {
	long double pi = acos(-1);
	Point ap = Point(a.x, a.y);
	Point bp = Point(b.x, b.y);
	Point dp = bp - ap;
	vector<pair<Point, Point>>ret;
	long double rad = atan2(dp.y, dp.x);
	long double d = hypot(dp.y, dp.x);
	if (a.r + b.r <= d) {
		long double newrad = asin((a.r + b.r) / d);
		{
			long double fd = hypot(inf, a.r);
			long double lrad = atan2(a.r, -inf);
			long double rrad = atan2(a.r, inf);
			pair<Point, Point>l = { Point(fd*cos(lrad + rad - newrad),fd*sin(lrad + rad - newrad)),Point(fd*cos(rrad + rad - newrad),fd*sin(rrad + rad - newrad)) };
			ret.push_back({ l.first + ap,l.second + ap });
		}
		newrad *= -1;
		{
			long double fd = hypot(inf, -a.r);
			long double lrad = atan2(-a.r, -inf);
			long double rrad = atan2(-a.r, inf);
			pair<Point, Point>l = { Point(fd*cos(lrad + rad - newrad),fd*sin(lrad + rad - newrad)),Point(fd*cos(rrad + rad - newrad),fd*sin(rrad + rad - newrad)) };
			ret.push_back({ l.first + ap,l.second + ap });
		}
	}
	if (abs(a.r - b.r) <= d) {
		long double newrad = asin(abs(a.r - b.r) / d);
		{
			long double fd = hypot(inf, a.r);
			long double lrad = atan2(a.r, -inf);
			long double rrad = atan2(a.r, inf);
			pair<Point, Point>l = { Point(fd*cos(lrad + rad - newrad),fd*sin(lrad + rad - newrad)),Point(fd*cos(rrad + rad - newrad),fd*sin(rrad + rad - newrad)) };
			ret.push_back({ l.first + ap,l.second + ap });
		}
		newrad *= -1;
		{
			long double fd = hypot(inf, -a.r);
			long double lrad = atan2(-a.r, -inf);
			long double rrad = atan2(-a.r, inf);
			pair<Point, Point>l = { Point(fd*cos(lrad + rad - newrad),fd*sin(lrad + rad - newrad)),Point(fd*cos(rrad + rad - newrad),fd*sin(rrad + rad - newrad)) };
			ret.push_back({ l.first + ap,l.second + ap });
		}
	}
	return ret;
}

struct Convex_hull {
	vector<Point>node;
	vector<Point>ret;
	bool line;
	Convex_hull(bool l) {
		line = l;
	}
	void Add_node(Point n) {
		node.push_back(n);
	}
	vector<Point>solve() {
		sort(node.begin(), node.end());
		int index = 0;
		int num = node.size();
		ret.resize(num * 2);
		for (int i = 0; i < num; i++) {
			if (line) {
				while (index > 1 && (ret[index - 1] - ret[index - 2]).det(node[i] - ret[index - 1]) < -EPS) {
					index--;
				}
			}
			else {
				while (index > 1 && (ret[index - 1] - ret[index - 2]).det(node[i] - ret[index - 1]) < EPS) {
					index--;
				}
			}
			ret[index++] = node[i];
		}
		int box = index;
		for (int i = num - 2; i >= 0; i--) {
			if (line) {
				while (index > box && (ret[index - 1] - ret[index - 2]).det(node[i] - ret[index - 1]) < -EPS) {
					index--;
				}
			}
			else {
				while (index > box && (ret[index - 1] - ret[index - 2]).det(node[i] - ret[index - 1]) < EPS) {
					index--;
				}
			}
			ret[index++] = node[i];
		}
		ret.resize(index - 1);
		return ret;
	}
};

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	while (cin >> N, N) {
		UnionFind uf(N);
		vector<Point>p(N * 2);
		for (auto &i : p)cin >> i.x >> i.y;
		for (int i = 0; i < N * 2; i += 2) {
			for (int j = i + 2; j < N * 2; j += 2) {
				if (LineCross(p[i], p[i + 1], p[j], p[j + 1])) {
					uf.Unite(i / 2, j / 2);
				}
			}
		}
		vector<int>ans(10);
		vector<int>sz(N);
		vector<int>corner(N);
		vector<int>not_corner(N);
		vector<vector<pair<Point, Point>>>vp(N);
		for (int i = 0; i < N; i++) {
			sz[uf.Find(i)]++;
		}
		for (int i = 0; i < N * 2; i += 2) {
			vp[uf.Find(i / 2)].push_back({ p[i], p[i + 1] });
			for (int j = i + 2; j < N * 2; j += 2) {
				if (LineCross(p[i], p[i + 1], p[j], p[j + 1])) {
					if (Distance(p[i], p[j]) <= EPS || Distance(p[i], p[j + 1]) <= EPS || Distance(p[i + 1], p[j]) <= EPS || Distance(p[i + 1], p[j + 1]) <= EPS) {
						corner[uf.Find(i / 2)]++;
					}
					else {
						not_corner[uf.Find(i / 2)]++;
					}
				}
			}
		}
		for (int i = 0; i < N; i++) {
			if (sz[i] == 0)continue;
			if (sz[i] == 1) {
				ans[1]++;
				continue;
			}
			if (sz[i] == 3) {
				if (corner[i] == 1)ans[4]++;
				else ans[7]++;
				continue;
			}
			if (sz[i] == 4) {
				if (corner[i] == 4)ans[0]++;
				else if (corner[i] == 2)ans[3]++;
				else ans[9]++;
				continue;
			}
			if (not_corner[i] == 1) {
				ans[6]++;
				continue;
			}
			if (not_corner[i] == 2) {
				ans[8]++;
				continue;
			}
			vector<vector<int>>edge(vp[i].size(),vector<int>(vp[i].size()));
			for (int j = 0; j < vp[i].size(); j++) {
				int num = 0;
				int idx = 0;
				for (int k = 0; k < vp[i].size(); k++) {
					if (j == k)continue;
					if (LineCross(vp[i][j].first, vp[i][j].second, vp[i][k].first, vp[i][k].second)) {
						edge[j][k] = 1;
					}
				}
			}
			for (int j = 0; j < vp[i].size(); j++) {
				if (accumulate(edge[j].begin(), edge[j].end(), 0) != 1)continue;
				int a = 0;
				for (int k = 0; k < edge[j].size(); k++) {
					if (edge[j][k])a = k;
				}
				int b = 0;
				for (int k = 0; k < edge[a].size(); k++) {
					if (edge[a][k] && k != j)b = k;
				}
				vector<Point>box;
				if (vp[i][a].first == vp[i][b].first) {
					box.push_back(vp[i][a].second);
					box.push_back(vp[i][a].first);
					box.push_back(vp[i][b].second);
				}
				else if (vp[i][a].first == vp[i][b].second) {
					box.push_back(vp[i][a].second);
					box.push_back(vp[i][a].first);
					box.push_back(vp[i][b].first);
				}
				else if (vp[i][a].second == vp[i][b].first) {
					box.push_back(vp[i][a].first);
					box.push_back(vp[i][a].second);
					box.push_back(vp[i][b].second);
				}
				else {
					box.push_back(vp[i][a].first);
					box.push_back(vp[i][a].second);
					box.push_back(vp[i][b].first);
				}
				long double arad = atan2l(box[1].y - box[0].y, box[1].x - box[0].x);
				long double brad = atan2l(box[2].y - box[1].y, box[2].x - box[1].x);
				brad -= arad;
				long double pi = acosl(-1);
				if (brad > pi)brad -= pi * 2;
				if (brad < -pi)brad += pi * 2;
				if (brad < 0)ans[2]++;
				else ans[5]++;
				break;
			}
		}
		for (int i = 0; i < 10; i++) {
			if (i)cout << " ";
			cout << ans[i];
		}
		cout << endl;
	}
}
accuracy: 1
time_ms: 50
memory_kb: 3644
final_rank: 14

code_snippet: #line 1 "a.cpp"
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
#line 2 "/home/kotatsugame/library/datastructure/UF.cpp"
struct UF{
	int n;
	vector<int>parent,rank;
	UF(int n_=0):n(n_),parent(n_),rank(n_,1)
	{
		for(int i=0;i<n_;i++)parent[i]=i;
	}
	int find(int a){return parent[a]!=a?parent[a]=find(parent[a]):a;}
	bool same(int a,int b){return find(a)==find(b);}
	bool unite(int a,int b)
	{
		a=find(a),b=find(b);
		if(a==b)return false;
		if(rank[a]<rank[b])
		{
			parent[a]=b;
			rank[b]+=rank[a];
		}
		else
		{
			parent[b]=a;
			rank[a]+=rank[b];
		}
		return true;
	}
	int size(int a){return rank[find(a)];}
};
#line 6 "a.cpp"
int N;
int X[1000][2],Y[1000][2];
bool touch(int i,int ik,int j,int jk)
{
	return X[i][ik]==X[j][jk]&&Y[i][ik]==Y[j][jk];
}
bool touch(int i,int j)
{
	return touch(i,0,j,0)||touch(i,0,j,1)||touch(i,1,j,0)||touch(i,1,j,1);
}
bool meet(int x,int y,int id)
{
	int a=X[id][0]-x,b=Y[id][0]-y;
	int c=X[id][1]-x,d=Y[id][1]-y;
	return a*d==b*c&&a*c+b*d<0;
}
main()
{
	while(cin>>N,N)
	{
		for(int i=0;i<N;i++)for(int j=0;j<2;j++)cin>>X[i][j]>>Y[i][j];
		UF uf(N);
		for(int i=0;i<N;i++)for(int k=0;k<2;k++)for(int j=0;j<N;j++)if(i!=j)
		{
			if(touch(i,j)||meet(X[i][k],Y[i][k],j))uf.unite(i,j);
		}
		vector<vector<int> >ids(N);
		for(int i=0;i<N;i++)ids[uf.find(i)].push_back(i);
		int ans[10]={};
		for(vector<int>id:ids)if(!id.empty())
		{
			vector<int>ok;
			bool middle=false;
			for(int i:id)
			{
				bool now=false;
				for(int j:id)if(i!=j)
				{
					if(touch(i,j))now=true;
					else
					{
						if(meet(X[i][0],Y[i][0],j)||meet(X[i][1],Y[i][1],j))middle=true;
					}
				}
				if(now)ok.push_back(i);
			}
			if(middle)
			{
				if(ok.size()==2)ans[4]++;
				else if(ok.size()==3)ans[3]++;
				else if(ok.size()==5)ans[6]++;
				else
				{
					vector<int>dist;
					for(int i:ok)
					{
						int dx=X[i][0]-X[i][1],dy=Y[i][0]-Y[i][1];
						dist.push_back(dx*dx+dy*dy);
					}
					sort(dist.begin(),dist.end());
					if(dist[0]==dist[1]&&dist[2]==dist[3])ans[8]++;
					else ans[9]++;
				}
			}
			else
			{
				if(ok.size()==0)ans[1]++;
				else if(ok.size()==3)ans[7]++;
				else if(ok.size()==4)ans[0]++;
				else
				{
					int s;
					for(int i:ok)
					{
						int cnt=0;
						for(int j:ok)if(i!=j&&touch(i,j))cnt++;
						if(cnt==1)
						{
							s=i;
							break;
						}
					}
					int g;
					for(int i:ok)if(i!=s&&touch(s,i))
					{
						g=i;
						break;
					}
					int sx,sy,gx,gy;
					if(touch(s,0,g,0))
					{
						sx=X[s][1]-X[s][0];
						sy=Y[s][1]-Y[s][0];
						gx=X[g][1]-X[g][0];
						gy=Y[g][1]-Y[g][0];
					}
					else if(touch(s,0,g,1))
					{
						sx=X[s][1]-X[s][0];
						sy=Y[s][1]-Y[s][0];
						gx=X[g][0]-X[g][1];
						gy=Y[g][0]-Y[g][1];
					}
					else if(touch(s,1,g,0))
					{
						sx=X[s][0]-X[s][1];
						sy=Y[s][0]-Y[s][1];
						gx=X[g][1]-X[g][0];
						gy=Y[g][1]-Y[g][0];
					}
					else
					{
						sx=X[s][0]-X[s][1];
						sy=Y[s][0]-Y[s][1];
						gx=X[g][0]-X[g][1];
						gy=Y[g][0]-Y[g][1];
					}
					if(sx*gy-sy*gx>0)ans[2]++;
					else ans[5]++;
				}
			}
		}
		for(int i=0;i<10;i++)cout<<ans[i]<<(i==9?"\n":" ");
	}
}
accuracy: 1
time_ms: 20
memory_kb: 3220
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=1005;
const int INF=1e6;
//const ll INF=1LL<<60;

//幾何ライブラリ

const double eps=1e-8;
const double pi=acos((long double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(int deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps&&fabs(y-p.y)<eps;
    }
};

typedef Point Vector;

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

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

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

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

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

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;

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

bool intersect(Point p1,Point p2,Point p3,Point p4){
    return(ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0&&ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}

bool intersect(Segment s1,Segment s2){
    return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        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);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

struct UF{
    int n;
    vector<int> par,size,cnt;
    vector<vector<int>> ver;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        cnt.assign(n,0);
        ver.assign(n,vector<int>());
        
        for(int i=0;i<n;i++){
            par[i]=i;
            ver[i].push_back(i);
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            cnt[root(a)]+=cnt[root(b)];
            for(int x:ver[root(b)]) ver[root(a)].push_back(x);
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N;cin>>N;
        if(N==0) break;
        
        UF uf;
        uf.init(N);
        vector<int> ans(10);
        
        vector<Segment> L(N);
        for(int i=0;i<N;i++){
            cin>>L[i].p1.x>>L[i].p1.y>>L[i].p2.x>>L[i].p2.y;
        }
        
        for(int i=0;i<N;i++){
            for(int j=i+1;j<N;j++){
                if(intersect(L[i],L[j])){
                    uf.unite(i,j);
                    if(L[i].p1==L[j].p1) uf.cnt[uf.root(i)]++;
                    if(L[i].p1==L[j].p2) uf.cnt[uf.root(i)]++;
                    if(L[i].p2==L[j].p1) uf.cnt[uf.root(i)]++;
                    if(L[i].p2==L[j].p2) uf.cnt[uf.root(i)]++;
                }
            }
        }
        
        for(int i=0;i<N;i++){
            if(uf.root(i)==i){
                if(uf.size[i]==1) ans[1]++;
                if(uf.size[i]==3){
                    if(uf.cnt[i]==1) ans[4]++;
                    if(uf.cnt[i]==2) ans[7]++;
                }
                if(uf.size[i]==4){
                    if(uf.cnt[i]==4) ans[0]++;
                    if(uf.cnt[i]==2) ans[3]++;
                    if(uf.cnt[i]==3) ans[9]++;
                }
                if(uf.size[i]==5){
                    int mu=0,aida=0;
                    for(int a:uf.ver[i]){
                        int cnt=0;
                        for(int b:uf.ver[i]){
                            if(a==b) continue;
                            if(intersect(L[a],L[b])){
                                if(L[a].p1==L[b].p1) cnt++;
                                else if(L[a].p1==L[b].p2) cnt++;
                                else if(L[a].p2==L[b].p1) cnt++;
                                else if(L[a].p2==L[b].p2) cnt++;
                                else aida++;
                            }
                        }
                        if(cnt==0) mu++;
                    }
                    if(mu) ans[8]++;
                    else if(aida) ans[6]++;
                    else{
                        int x=0;
                        for(int a:uf.ver[i]){
                            bool c=0,d=0;
                            for(int b:uf.ver[i]){
                                if(a==b) continue;
                                if(L[a].p1==L[b].p1) c=1;
                                else if(L[a].p1==L[b].p2) c=1;
                                else if(L[a].p2==L[b].p1) d=1;
                                else if(L[a].p2==L[b].p2) d=1;
                            }
                            if(!c){
                                for(int b:uf.ver[i]){
                                    if(a==b) continue;
                                    if(L[a].p2==L[b].p1){
                                        int w=ccw(L[a].p1,L[a].p2,L[b].p2);
                                        if(w==1) x++;
                                    }
                                    if(L[a].p2==L[b].p2){
                                        int w=ccw(L[a].p1,L[a].p2,L[b].p1);
                                        if(w==1) x++;
                                    }
                                }
                            }else if(!d){
                                for(int b:uf.ver[i]){
                                    if(a==b) continue;
                                    if(L[a].p1==L[b].p1){
                                        int w=ccw(L[a].p2,L[a].p1,L[b].p2);
                                        if(w==1) x++;
                                    }
                                    if(L[a].p1==L[b].p2){
                                        int w=ccw(L[a].p2,L[a].p1,L[b].p1);
                                        if(w==1) x++;
                                    }
                                }
                            }
                        }
                        
                        if(x) ans[5]++;
                        else ans[2]++;
                    }
                }
            }
        }
        
        for(int i=0;i<10;i++){
            if(i) cout<<" ";
            cout<<ans[i];
        }
        cout<<endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3592
final_rank: 13

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


#define NUM 1005

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{
		return x != p.x? x < p.x: y < p.y;
	}

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

	double x,y;
};

struct Line{
public:
	Point p[2];
	Line(Point p1,Point p2){
		p[0] = p1;
		p[1] = p2;
	}
};

typedef Point Vector;


int N;
int boss[NUM],height[NUM];
int ANS[11];
vector<Line> LINE,GROUP[NUM];

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

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

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

double abs(Line a){

	return sqrt((a.p[0].x-a.p[1].x)*(a.p[0].x-a.p[1].x)+(a.p[0].y-a.p[1].y)*(a.p[0].y-a.p[1].y));
}

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

//点と直線の距離
double calc_dist1(Line line,Point point){
    return abs(cross(line.p[1]-line.p[0],point-line.p[0]))/abs(line.p[1]-line.p[0]);
}

double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[0].y-A.p[1].y)/(A.p[0].x-A.p[1].x);
	}
}

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(x1 != x2){
		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);
}

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

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 get_boss(int id){
	if(boss[id] == id)return id;
	else{
		return boss[id] = get_boss(boss[id]);
	}
}

int is_same(int x,int y){
	return get_boss(x) == get_boss(y);
}

void unite(int x,int y){
	int boss_x = get_boss(x);
	int boss_y = get_boss(y);

	if(boss_x == boss_y)return;

	if(height[x] > height[y]){

		boss[boss_y] = boss_x;

	}else if(height[x] < height[y]){

		boss[boss_x] = boss_y;

	}else{ //height[x] == height[y]

		boss[boss_y] = boss_x;
		height[x]++;
	}
}

void init(){

	for(int i = 0; i < N; i++){
		boss[i] = i;
		height[i] = 0;
	}
}

void func(){

	for(int i = 0; i <= 10; i++){
		ANS[i] = 0;
	}
	LINE.clear();

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

		GROUP[i].clear();
	}

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

		Point a,b;

		scanf("%lf %lf %lf %lf",&a.x,&a.y,&b.x,&b.y);
		LINE.push_back(Line(a,b));
	}

	init();

	//交差する直線をuniteする
	for(int i = 0; i < N-1; i++){
		for(int k = i+1; k < N; k++){
			if(check_Cross(LINE[i],LINE[k])){
				unite(i,k);
			}
		}
	}

	//線分を、各グループに仕分けする
	for(int i = 0; i < N; i++){

		GROUP[get_boss(i)].push_back(LINE[i]);
	}

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

		if(GROUP[i].size() == 0)continue;

		//交差の回数を数える
		int num_cross = 0;

		for(int a = 0; a < GROUP[i].size()-1; a++){
			for(int b = a+1; b < GROUP[i].size(); b++){
				if(check_Cross(GROUP[i][a],GROUP[i][b])){
					num_cross++;
				}
			}
		}

		bool FLG;

		switch(num_cross){
		case 0:

			ANS[1]++;
			break;
		case 2: //4か7

			FLG = true;
			//交点が全て端点に含まれていれば7
			for(int a = 0; a < 2; a++){
				for(int b = a+1; b < 3; b++){
					if(!check_Cross(GROUP[i][a],GROUP[i][b]))continue;

					Point ret = calc_Cross_Point(GROUP[i][a].p[0],GROUP[i][a].p[1],GROUP[i][b].p[0],GROUP[i][b].p[1]);

					if((ret == GROUP[i][a].p[0]|| ret == GROUP[i][a].p[1]) && (ret == GROUP[i][b].p[0]|| ret == GROUP[i][b].p[1])){

						//Do nothing

					}else{

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

			if(FLG){

				ANS[7]++;

			}else{

				ANS[4]++;
			}


			break;
		case 3:
			;
			ANS[3]++;
			break;
		case 4: //0,2,5,9のいずれか

			if(GROUP[i].size() == 4){ //0か9

				FLG = true;

				//端点以外で交点を持つなら9
				for(int a = 0; a < 3; a++){
					for(int b = a+1; b < 4; b++){
						if(!check_Cross(GROUP[i][a],GROUP[i][b]))continue;

						if(GROUP[i][a].p[0] == GROUP[i][b].p[0] || GROUP[i][a].p[0] == GROUP[i][b].p[1] ||
								GROUP[i][a].p[1] == GROUP[i][b].p[0] || GROUP[i][a].p[1] == GROUP[i][b].p[1]){

							//Do nothing

						}else{

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

				if(FLG){

					ANS[0]++;
				}else{

					ANS[9]++;
				}

			}else{ //2か5

				//交差回数が1の線分を探し、それと交差回数2の線分の、交点ではない端点との位置関係を見る
				int count,index_1,index_2;

				for(int a = 0; a < 5; a++){
					count = 0;
					for(int b = 0; b < 5; b++){
						if(b == a)continue;

						if(check_Cross(GROUP[i][a],GROUP[i][b])){
							count++;
						}
					}
					if(count == 1){

						index_1 = a;
						break;
					}
				}

				for(int a = 0; a < 5; a++){
					if(a == index_1 || check_Cross(GROUP[i][index_1],GROUP[i][a]) == false)continue;

					index_2 = a;
					break;
				}

				Point A,B,C;

				if(GROUP[i][index_1].p[0] == GROUP[i][index_2].p[0]){

					A = GROUP[i][index_1].p[1];
					B = GROUP[i][index_1].p[0];
					C = GROUP[i][index_2].p[1];

				}else if(GROUP[i][index_1].p[0] == GROUP[i][index_2].p[1]){

					A = GROUP[i][index_1].p[1];
					B = GROUP[i][index_1].p[0];
					C = GROUP[i][index_2].p[0];

				}else if(GROUP[i][index_1].p[1] == GROUP[i][index_2].p[0]){

					A = GROUP[i][index_1].p[0];
					B = GROUP[i][index_1].p[1];
					C = GROUP[i][index_2].p[1];


				}else{ //GROUP[i][index_1].p[1] == GROUP[i][index_2].p[1]

					A = GROUP[i][index_1].p[0];
					B = GROUP[i][index_1].p[1];
					C = GROUP[i][index_2].p[0];

				}

				if(ccw(A,B,C) == CLOCKWISE){

					ANS[2]++;

				}else{

					ANS[5]++;
				}
			}

			break;
		case 5:

			ANS[6]++;
			break;
		case 6:

			ANS[8]++;
			break;
		}
	}

	printf("%d",ANS[0]);
	for(int i = 1; i <= 9; i++){

		printf(" %d",ANS[i]);
	}
	printf("\n");
}

int main(){

	while(true){

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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3372
final_rank: 11

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<stack>
#include<bitset>
#include<numeric>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
const ll mod = 1000000007;
const long double eps = 1e-8;
typedef pair<int, int> P;

typedef long double ld;

#include<complex>
typedef complex<ld> Point;
const ld pi = acos(-1.0);
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }
namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
bool eq(Point a, Point b) {
	return abs(a - b) < eps;
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	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; //a--c--b on line
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a)*cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
bool isis_lp(Line l, Point p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}
//点が線分上に存在するか
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
//線分と線分の交差判定
bool isis_ss(Line s, Line t) {
	if (isis_sp(t, s.a) || isis_sp(t, s.b) || isis_sp(s, t.a) || isis_sp(s, t.b))return true;
	return(cross(s.b - s.a, t.a - s.a)*cross(s.b - s.a, t.b - s.a) < -eps && cross(t.b - t.a, s.a - t.a)*cross(t.b - t.a, s.b - t.a) < -eps);
}
//点から直線への垂線の足
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	//if (cross(tv, sv) == 0)return { 0,0 };
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
//直線と点の距離
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
//直線と直線の距離
ld dist_ll(Line l, Line m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}
//線分と直線の距離
ld dist_ls(Line l, Line s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}
//線分と点の距離
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}
//線分と線分の距離
ld dist_ss(Line s, Line t) {
	if (isis_ss(s, t))return 0;
	return min({ dist_sp(s,t.a),dist_sp(s,t.b),dist_sp(t,s.a),dist_sp(t,s.b) });
}

int distingish_number(vector<Line> &v) {
	if (v.size() == 1)return 1;
	if (v.size() == 3) {
		vector<Point> p;
		rep(i, 3) {
			Rep(j, i + 1, 3) {
				Line lhs = v[i], rhs = v[j];
				if (isis_ss(lhs, rhs)) {
					Point c = is_ll(lhs, rhs);
					p.push_back(c);
				}
			}
		}
		//
		if (p.size() != 2)return 0;
		//
		rep(i, 2) {
			int cnt = 0;
			rep(j, 3) {
				Line l = v[j];
				if (eq(l.a, p[i]) || eq(l.b, p[i]))cnt++;
			}
			if (cnt != 2)return 4;
		}
		return 7;
	}
	if (v.size() == 4) {
		vector<Point> p;
		rep(i, 4) {
			Rep(j, i + 1, 4) {
				Line lhs = v[i], rhs = v[j];
				if (isis_ss(lhs, rhs)) {
					Point c = is_ll(lhs, rhs);
					p.push_back(c);
				}
			}
		}
		if (p.size() == 3)return 3;
		//
		if (p.size() != 4)return 0;
		//
		rep(i, 4) {
			int cnt = 0;
			rep(j, 4) {
				Line l = v[j];
				if (eq(l.a, p[i]) || eq(l.b, p[i]))cnt++;
			}
			if (cnt != 2)return 9;
		}
		return 0;
	}
	vector<Point> p;
	rep(i, 5) {
		Rep(j, i + 1, 5) {
			Line lhs = v[i], rhs = v[j];
			if (isis_ss(lhs, rhs)) {
				Point c = is_ll(lhs, rhs);
				p.push_back(c);
			}
		}
	}
	if (p.size() == 6)return 8;
	if (p.size() == 5)return 6;
	if (p.size() != 4)return 0;
	ld ma = -1;
	int le, ri;
	rep(i, 4)Rep(j, i + 1, 4) {
		if (abs(p[i] - p[j]) > ma) {
			ma = abs(p[i] - p[j]); le = i, ri = j;
		}
	}
	ma = -1;
	int le2, ri2;
	rep(i, 4) {
		if (i == le || i == ri)continue;
		if (abs(p[i] - p[ri]) > ma) {
			ma = abs(p[i] - p[ri]);
			le2 = i;
		}
	}
	ri2 = 6 - le - ri - le2;
	if (ccw(p[le], p[le2], p[ri2]) == -1)return 2;
	return 5;
}

int n;
void solve() {
	vector<Line> v(n);
	vector<bool> used(n, false);
	rep(i, n) {
		Point a, b;
		ld x, y; cin >> x >> y; a = { x,y };
		cin >> x >> y; b = { x,y };
		v[i] = { a,b };
	}
	int cnt[10] = {};
	rep(i, n) {
		if (used[i])continue;
		vector<Line> u; u.push_back(v[i]); used[i] = true;
		rep(aa, 5) {
			Rep(j, i + 1, n) {
				if (used[j])continue;
				bool f = false;
				rep(k, u.size()) {
					if (isis_ss(u[k], v[j])) {
						f = true; break;
					}
				}
				if (f) {
					u.push_back(v[j]);
					used[j] = true;
				}
			}
		}
		//cout <<"???"<< u.size() << endl;
		cnt[distingish_number(u)]++;
	}
	rep(i, 10) {
		if (i > 0)cout << " ";
		cout << cnt[i];
	}
	cout << endl;
}
signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	while (cin >> n, n) {
		solve();
	}
	//stop
	return 0;
}
accuracy: 1
time_ms: 3920
memory_kb: 3388
final_rank: 20

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

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

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

        vector<L> ls(n);
        for(int i=0; i<n; i++){
            int xs,ys,xt,yt;
            cin >> xs >> ys >> xt >> yt;
            ls[i] = L(P(xs, ys), P(xt, yt));
        }

        int ans[10] = {};
        while(!ls.empty()){
            L beg = ls.back();
            ls.pop_back();
            vector<L> cluster(1, beg);
            queue<L> wait;
            wait.push(beg);
            while(!wait.empty()){
                L curr = wait.front();
                wait.pop();
                for(int i=0; i<(int)ls.size(); i++){
                    if(intersectSS(curr, ls[i])){
                        wait.push(ls[i]);
                        cluster.push_back(ls[i]);
                        ls.erase(ls.begin() +i);
                        i--;
                    }
                }
            }

            //各クラスタについて辺を分類
            int m = cluster.size();
            vector<vector<int> > ep(m, vector<int>(2, 0)), mp(m, vector<int>(2, 0));
            int ee=0, ex=0, em=0, xm=0, mm=0;
            for(int i=0; i<m; i++){
                int endpoint=0, mid=0;
                for(int j=0; j<m; j++){
                    if(i==j) continue;
                    for(int d=0; d<2; d++){
                        if(cluster[i][d] == cluster[j][0] || cluster[i][d] == cluster[j][1]){
                            endpoint++;
                            ep[i][d]++;
                            continue;
                        }
                        if(intersectSP(cluster[j], cluster[i][d])){
                            mid++;
                            mp[i][d]++;
                        }
                    }
                }
                if(endpoint == 2){
                    ee++;
                }else if(endpoint == 1){
                    if(mid == 1) em++;
                    else ex++;
                }else{
                    if(mid == 2) mm++;
                    if(mid == 1) xm++;
                }
            }

            if(ee==3 && ex==2){
                int num = 0;
                VP ps(3);
                for(int i=0; i<m; i++){
                    for(int d=0; d<2; d++){
                        if(ep[i][d] == 0){
                            ps[num] = cluster[i][d];
                            num++;
                            ps[2] = cluster[i][1-d];
                        }
                    }
                }
                if(ccw(ps[0], ps[1], ps[2]) == 1){
                    ans[5]++;
                }else{
                    ans[2]++;
                }
            }else if(mm == 1){
                ans[8]++;
            }else if(xm == 1){
                ans[3]++;
            }else if(ee == 0){
                if(ex == 1){
                    ans[4]++;
                }else{
                    ans[1]++;
                }
            }else if(ee == 1){
                ans[7]++;
            }else if(ee == 2){
                ans[9]++;
            }else if(ee == 3){
                ans[6]++;
            }else{
                ans[0]++;
            }
        }

        for(int i=0; i<9; i++){
            cout << ans[i] << " ";
        }
        cout << ans[9] << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3036
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

const double eps = 1e-6;

using Point = pair<int,int>;
using Line = pair<Point,Point>;

inline Line read_L(){
    Point p1,p2;
    cin >>p1.fi >>p1.se >>p2.fi >>p2.se;
    if(p1>p2) swap(p1,p2);
    return {p1,p2};
}

double dist(double px, double py, double qx, double qy){
    return sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py));
}

bool on(Line l, Point p){
    Point q1 = l.fi, q2 = l.se;
    int dx = q2.fi - q1.fi, dy = q2.se - q1.se;

    double t;
    if(dx != 0) t = (double)(p.fi-q1.fi)/dx;
    else t = (double)(p.se-q1.se)/dy;

    double px = q1.fi + t*dx;
    double py = q1.se + t*dy;

    if(0<t && t<1){
        return (dist(px,py,p.fi,p.se) < eps);
    }
    return false;
}

int isec(Line l, Line m){
    if(l.fi == m.fi || l.fi == m.se || l.se == m.fi || l.se == m.se) return 1;
    if(on(l,m.fi) || on(l,m.se) || on(m,l.fi) || on(m,l.se)) return 2;
    return 0;
}

int recognize(const vector<Line> &v){
    // 棒の本数
    int V = v.size();

    set<Point> s;
    map<Point,int> ct;
    rep(i,V){
        s.insert(v[i].fi);
        s.insert(v[i].se);
        ++ct[v[i].fi];
        ++ct[v[i].se];
    }

    // 頂点の数
    int S = s.size();

    if(V==4 && S==4) return 0;
    if(V==1 && S==2) return 1;
    if(V==4 && S==6) return 3;
    if(V==3 && S==5) return 4;
    if(V==3 && S==4) return 7;
    if(V==4 && S==5) return 9;

    int two = 0;
    rep(i,V){
        if(ct[v[i].fi]==1 && ct[v[i].se]==1) ++two;
    }
    if(two==1) return 8;

    rep(i,V)rep(j,i){
        if(isec(v[i],v[j])==2) return 6;
    }

    // 2 or 5

    // parallel 3 lines
    map<pair<int,int>,int> d_ct;
    vector<pair<int,int>> d(V);
    rep(i,V){
        Point p1 = v[i].fi, p2 = v[i].se;
        int dx = p2.fi-p1.fi, dy = p2.se-p1.se;
        int G = __gcd(dx,dy);
        dx /= G;
        dy /= G;
        d[i] = {dx,dy};

        ++d_ct[d[i]];
    }

    // printf("d_ct:\n");
    // for(const auto &pp:d_ct) dbg(pp);

    vector<pair<double,Line>> p_l;
    rep(i,V)if(d_ct[d[i]]==3){

        // y-y1 = (y2-y1)/(x2-x1) (x-x1)
        // (y2-y1)(x-x1) - (x2-x1)(y-y1) = 0
        // (y2-y1)x - (x2-x1)y  -(y2-y1)x1 + (x2-x1)y1 = 0
        int x1 = v[i].fi.fi, y1 = v[i].fi.se;
        int x2 = v[i].se.fi, y2 = v[i].se.se;

        int A = y2-y1, B = -(x2-x1);
        int C = -(y2-y1)*x1 + (x2-x1)*y1;

        if(B==0){
            p_l.pb({C/(double)A ,v[i]});
        }
        else{
            p_l.pb({-C/(double)B ,v[i]});
        }
    }

    sort(all(p_l));
    // dbg(p_l);

    Line two_checker(p_l[1].se.se, p_l[2].se.se);
    if(two_checker.fi > two_checker.se) swap(two_checker.fi, two_checker.se);
    // dbg(two_checker);
    rep(i,V)if(v[i] == two_checker) return 2;
    return 5;
}

const int N = 1000;
vector<int> G[N];

int main(){
    int n;
    while(cin >>n,n){
        rep(i,N) G[i].clear();

        vector<Line> l(n);
        rep(i,n) l[i] = read_L();

        rep(i,n)rep(j,i){
            if(isec(l[i],l[j])!=0){
                G[i].pb(j);
                G[j].pb(i);
            }
        }

        int ans[10]={};
        vector<bool> vis(n);
        rep(i,n)if(!vis[i]){
            queue<int> que;
            vector<Line> cc;

            vis[i] = true;
            que.push(i);
            cc.pb(l[i]);
            while(!que.empty()){
                int v = que.front();
                que.pop();
                for(int nx:G[v]){
                    if(!vis[nx]){
                        vis[nx] = true;
                        que.push(nx);
                        cc.pb(l[nx]);
                    }
                }
            }

            int idx = recognize(cc);
            ++ans[idx];
        }

        rep(i,10) cout << ans[i] << " \n"[i==9];
    }
    return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3176
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ld = long double;
using point = complex<ld>;

constexpr ld eps = 1e-10;

bool comp(point a, point b) {
    return (real(a - b) * 1.347589 + imag(a - b)) > 0;
}

ld dot(point a, point b) {
    return real(conj(a) * b);
}

ld cross(point a, point b) {
    return imag(conj(a) * b);
}

vector<point> unique(vector<point> ps) {
    sort(begin(ps), end(ps), comp);
    vector<point> res;
    for(auto& p : ps) {
        if(res.empty() || abs(res.back() - p) > eps) {
            res.push_back(p);
        }
    }
    return res;
}

struct segment {
    segment(point a, point b) : a(a), b(b) {}
    bool operator<(segment other) const {
        return min(real(a), real(b)) < min(real(other.a), real(other.b));
    }
    point a, b;
};

int ccw(point a, point b, point c) {
    b -= a; c -= a;
    if(cross(b, c) > eps)           return 1;  // a -> b -> c : counterclockwise
    if(cross(b, c) < -eps)          return -1; // a -> b -> c : clockwise
    if(dot(b, c) < 0)               return 2;  // c -> a -> b : line
    if(std::norm(b) < std::norm(c)) return -2; // a -> b -> c : line
    return 0;                                  // a -> c -> b : line
}

bool isis_ss(segment s, segment t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0
        && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

point rotate(point p, ld theta) {
    const ld x = real(p), y = imag(p);
    return point(x * cos(theta) - y * sin(theta), x * sin(theta) + y * cos(theta));
}

int main() {
    int n;
    while(cin >> n, n) {
        vector<segment> ss;
        for(int i = 0; i < n; ++i) {
            ld x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            ss.emplace_back(point(x1, y1), point(x2, y2));
        }
        vector<vector<int>> g(n, vector<int>(n));
        for(int i = 0; i < n; ++i) {
            for(int j = i + 1; j < n; ++j) {
                if(isis_ss(ss[i], ss[j])) {
                    g[i].push_back(j);
                    g[j].push_back(i);
                }
            }
        }
        vector<vector<segment>> digits;
        vector<bool> used(n);
        function<void(int, vector<segment>&)> dfs = [&](int v, vector<segment>& d) {
            used[v] = true;
            d.push_back(ss[v]);
            for(auto to : g[v]) {
                if(used[to]) continue;
                dfs(to, d);
            }
        };
        for(int i = 0; i < n; ++i) {
            if(used[i]) continue;
            vector<segment> digit;
            dfs(i, digit);
            digits.push_back(move(digit));
        }

        vector<int> ans(10);
        for(auto& d : digits) {
            if(d.size() == 1) {
                ans[1]++;
            } else if(d.size() == 3 || d.size() == 4) {
                vector<point> ps;
                for(auto& s : d) {
                    ps.push_back(s.a);
                    ps.push_back(s.b);
                }
                ps = unique(ps);
                if(ps.size() == 4) {
                    ans[d.size() == 3 ? 7 : 0]++;
                } else if(ps.size() == 5) {
                    ans[d.size() == 3 ? 4 : 9]++;
                } else if(ps.size() == 6) {
                    ans[3]++;
                } else {
                    assert(false); // !unreachable()
                }
            } else {
                int is_eight_or_six = 0;
                for(auto& s : d) {
                    int cnt = 0;
                    for(auto& s2 : d) {
                        cnt += isis_ss(s, s2);
                    }
                    is_eight_or_six += cnt == 4;
                }
                if(is_eight_or_six == 2) {
                    ans[8] += 1;
                } else if(is_eight_or_six == 1) {
                    ans[6] += 1;
                } else {
                    const ld rad = -arg(d[0].a - d[0].b);
                    vector<segment> hori, vert;
                    for(auto& s : d) {
                        s.a = rotate(s.a, rad);
                        s.b = rotate(s.b, rad);
                        if(abs(real(s.a) - real(s.b)) < eps) {
                            vert.push_back(s);
                        } else {
                            hori.push_back(s);
                        }
                    }

                    if(hori.size() == 2) {
                        if(hori[1] < hori[0]) swap(hori[0], hori[1]);
                        if(imag(hori[0].a) > imag(hori[1].a)) {
                            ans[2] += 1;
                        } else {
                            ans[5] += 1;
                        }
                    } else if(vert.size() == 2) {
                        if(vert[1] < vert[0]) swap(vert[0], vert[1]);
                        if(min(imag(vert[0].a), imag(vert[0].b)) > min(imag(vert[1].a), imag(vert[1].b))) {
                            ans[5] += 1;
                        } else {
                            ans[2] += 1;
                        }
                    } else {
                        assert(false); // !unreachable()
                    }
                }
            }
        }
        for(int i = 0; i < 10; ++i) {
            cout << ans[i] << " \n"[i + 1 == 10];
        }
    }
}
accuracy: 1
time_ms: 180
memory_kb: 9732
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const double EPS = 1e-8;
const double INF = 1e12;
typedef complex<double> P;
namespace std{
	bool operator < (const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
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);
}

struct L : public vector<P>{
	L(){}
	L(const P &a, const P &b){
		push_back(a); push_back(b);
	}
};

struct C{
	P p; double r;
	C(const P &p, double r) : p(p), r(r){}
};

int ccw(P a, P b, P 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 L &l, const L &m){
	return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || // non-parallel
		abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;   // same line
}
bool intersectLS(const L &l, const L &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 L &l, const P &p){
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
bool intersectSS(const L &s, const L &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 intersectSP(const L &s, const P &p){
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; // triangle inequality
}

struct UnionFind{
	vector<int> par;
	int cnt;
	UnionFind(int size_) : par(size_, -1), cnt(size_){}
	void unite(int x, int y){
		if((x = find(x)) != (y = find(y))){
			if(par[y] < par[x]) swap(x, y);
			par[x] += par[y]; par[y] = x; cnt--;
		}
	}
	bool same(int x, int y){ return find(x) == find(y); }
	int find(int x){ return par[x] < 0 ? x : par[x] = find(par[x]); }
	int size(int x){ return -par[find(x)]; }
	int size(){ return cnt; }
};

L l[1000];
vector<int> G[1000];
map<vector<int>, int> m;

int check(vector<int> g){
	if(g.size() == 0) return -1;
	if(g.size() == 1) return 1;
	if(g.size() == 2) return -1;

	for(int i = 0; i < g.size(); i++){
		P v1 = l[g[i]][0] - l[g[i]][1];
		for(int j = i + 1; j < g.size(); j++){
			if(i == j) continue;
			P v2 = l[g[j]][0] - l[g[j]][1];
			double d = dot(v1, v2);
			double c = cross(v1, v2);
			if(d < EPS || c < EPS) continue;
			return -1;
		}
	}

	vector<int> num(6);
	for(int i = 0; i < g.size(); i++){
		int same = 0, mid = 0;
		L l1 = l[g[i]];
		for(int j = 0; j < g.size(); j++){
			if(i == j) continue;
			L l2 = l[g[j]];
			if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
				same++;
			}
			else if(intersectSP(l2, l1[0]) || intersectSP(l2, l1[1])){
				mid++;
			}
		}
		if(same == 0 && mid == 0) num[0]++;
		if(same == 1 && mid == 0) num[1]++;
		if(same == 2 && mid == 0) num[2]++;
		if(same == 1 && mid == 1) num[3]++;
		if(same == 0 && mid == 2) num[4]++;
		if(same == 0 && mid == 1) num[5]++;
	}

	int ret = -1;
	if(m.count(num)) ret = m[num];

	if(ret == 2){
		for(int i = 0; i < g.size(); i++){
			int same = 0, mid = 0;
			L l1 = l[g[i]];
			L ll;
			P p;
			for(int j = 0; j < g.size(); j++){
				if(i == j) continue;
				L l2 = l[g[j]];
				if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
					same++;
					if(l1[0] == l2[0] || l1[0] == l2[1]) p = l1[0];
					else p = l1[1];
					ll = l2;
				}
			}
			if(same == 1 && mid == 0){
				P p1 = l1[0], p2 = l1[1];
				if(p2 == p) swap(p1, p2);
				P v1 = p2 - p1;
				p1 = ll[0], p2 = ll[1];
				if(p2 == p) swap(p1, p2);
				P v2 = p2 - p1;

				double c = cross(v1, v2);
				if(c < 0) ret = 5;
			}
		}
	}
	return ret;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
#ifdef LOCAL
	std::ifstream in("in");
	std::cin.rdbuf(in.rdbuf());
#endif

	m[{ 0, 0, 4, 0, 0, 0 }] = 0;
	m[{ 1, 0, 4, 0, 0, 0 }] = 1;
	m[{ 0, 2, 3, 0, 0, 0 }] = 2;
	m[{ 0, 2, 1, 0, 0, 1 }] = 3;
	m[{ 1, 1, 0, 1, 0, 0 }] = 4;
	//m[{ 0, 2, 3, 0, 0, 0 }] = 5;
	m[{ 0, 1, 3, 1, 0, 0 }] = 6;
	m[{ 0, 2, 1, 0, 0, 0 }] = 7;
	m[{ 0, 0, 4, 0, 1, 0 }] = 8;
	m[{ 0, 1, 2, 1, 0, 0 }] = 9;

	int N;
	while(cin >> N, N){
		for(int i = 0; i < N; i++){
			double x1, y1, x2, y2;
			cin >> x1 >> y1 >> x2 >> y2;
			l[i] = L(P(x1, y1), P(x2, y2));
		}

		for(int i = 0; i < N; i++){
			G[i].clear();
		}

		UnionFind uf(N);
		for(int i = 0; i < N; i++){
			for(int j = i + 1; j < N; j++){
				if(intersectSS(l[i], l[j])) uf.unite(i, j);
			}
		}
		for(int i = 0; i < N; i++){
			int p = uf.find(i);
			G[p].push_back(i);
		}

		int ans[10] = { 0 };
		for(int i = 0; i < N; i++){
			int res = check(G[i]);
			if(res != -1) ans[res]++;
		}

		for(int i = 0; i < 10; i++){
			cout << ans[i] << (i != 9 ? " " : "");
		}
		cout << endl;
	}


}
accuracy: 1
time_ms: 40
memory_kb: 3312
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const double EPS = 1e-8;
const double INF = 1e12;
typedef complex<double> P;
namespace std{
	bool operator < (const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}
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);
}

struct L : public vector<P>{
	L(){}
	L(const P &a, const P &b){
		push_back(a); push_back(b);
	}
};

struct C{
	P p; double r;
	C(const P &p, double r) : p(p), r(r){}
};

int ccw(P a, P b, P 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 L &l, const L &m){
	return abs(cross(l[1] - l[0], m[1] - m[0])) > EPS || // non-parallel
		abs(cross(l[1] - l[0], m[0] - l[0])) < EPS;   // same line
}
bool intersectLS(const L &l, const L &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 L &l, const P &p){
	return abs(cross(l[1] - p, l[0] - p)) < EPS;
}
bool intersectSS(const L &s, const L &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 intersectSP(const L &s, const P &p){
	return abs(s[0] - p) + abs(s[1] - p) - abs(s[1] - s[0]) < EPS; // triangle inequality
}

struct UnionFind{
	vector<int> par;
	int cnt;
	UnionFind(int size_) : par(size_, -1), cnt(size_){}
	void unite(int x, int y){
		if((x = find(x)) != (y = find(y))){
			if(par[y] < par[x]) swap(x, y);
			par[x] += par[y]; par[y] = x; cnt--;
		}
	}
	bool same(int x, int y){ return find(x) == find(y); }
	int find(int x){ return par[x] < 0 ? x : par[x] = find(par[x]); }
	int size(int x){ return -par[find(x)]; }
	int size(){ return cnt; }
};

L l[1000];
vector<int> G[1000];
map<vector<int>, int> m;

int check(vector<int> g){
	if(g.size() == 0) return -1;
	if(g.size() == 1) return 1;
	if(g.size() == 2) return -1;

	for(int i = 0; i < g.size(); i++){
		P v1 = l[g[i]][0] - l[g[i]][1];
		for(int j = i + 1; j < g.size(); j++){
			if(i == j) continue;
			P v2 = l[g[j]][0] - l[g[j]][1];
			double d = dot(v1, v2);
			double c = cross(v1, v2);
			if(d < EPS || c < EPS) continue;
			return -1;
		}
	}

	vector<int> num(6);
	for(int i = 0; i < g.size(); i++){
		int same = 0, mid = 0;
		L l1 = l[g[i]];
		for(int j = 0; j < g.size(); j++){
			if(i == j) continue;
			L l2 = l[g[j]];
			if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
				same++;
			}
			else if(intersectSP(l2, l1[0]) || intersectSP(l2, l1[1])){
				mid++;
			}
		}
		if(same == 0 && mid == 0) num[0]++;
		if(same == 1 && mid == 0) num[1]++;
		if(same == 2 && mid == 0) num[2]++;
		if(same == 1 && mid == 1) num[3]++;
		if(same == 0 && mid == 2) num[4]++;
		if(same == 0 && mid == 1) num[5]++;
	}

	int ret = -1;
	if(m.count(num)) ret = m[num];

	if(ret == 2){
		for(int i = 0; i < g.size(); i++){
			int same = 0, mid = 0;
			L l1 = l[g[i]];
			L ll;
			P p;
			for(int j = 0; j < g.size(); j++){
				if(i == j) continue;
				L l2 = l[g[j]];
				if(l1[0] == l2[0] || l1[1] == l2[1] || l1[0] == l2[1] || l1[1] == l2[0]){
					same++;
					if(l1[0] == l2[0] || l1[0] == l2[1]) p = l1[0];
					else p = l1[1];
					ll = l2;
				}
				else if(intersectSP(l2, l1[0]) || intersectSP(l2, l1[1])){
					mid++;
				}
			}
			if(same == 1 && mid == 0){
				P p1 = l1[0], p2 = l1[1];
				if(p2 == p) swap(p1, p2);
				P v1 = p2 - p1;
				p1 = ll[0], p2 = ll[1];
				if(p2 == p) swap(p1, p2);
				P v2 = p2 - p1;

				double c = cross(v1, v2);
				if(c < 0) ret = 5;
			}
		}
	}
	return ret;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
#ifdef LOCAL
	std::ifstream in("in");
	std::cin.rdbuf(in.rdbuf());
#endif

	m[{ 0, 0, 4, 0, 0, 0 }] = 0;
	m[{ 1, 0, 4, 0, 0, 0 }] = 1;
	m[{ 0, 2, 3, 0, 0, 0 }] = 2;
	m[{ 0, 2, 1, 0, 0, 1 }] = 3;
	m[{ 1, 1, 0, 1, 0, 0 }] = 4;
	//m[{ 0, 2, 3, 0, 0, 0 }] = 5;
	m[{ 0, 1, 3, 1, 0, 0 }] = 6;
	m[{ 0, 2, 1, 0, 0, 0 }] = 7;
	m[{ 0, 0, 4, 0, 1, 0 }] = 8;
	m[{ 0, 1, 2, 1, 0, 0 }] = 9;

	int N;
	while(cin >> N, N){
		for(int i = 0; i < N; i++){
			double x1, y1, x2, y2;
			cin >> x1 >> y1 >> x2 >> y2;
			l[i] = L(P(x1, y1), P(x2, y2));
		}

		for(int i = 0; i < N; i++){
			G[i].clear();
		}

		UnionFind uf(N);
		for(int i = 0; i < N; i++){
			for(int j = i + 1; j < N; j++){
				if(intersectSS(l[i], l[j])) uf.unite(i, j);
			}
		}
		for(int i = 0; i < N; i++){
			int p = uf.find(i);
			G[p].push_back(i);
		}

		int ans[10] = { 0 };
		for(int i = 0; i < N; i++){
			int res = check(G[i]);
			if(res != -1) ans[res]++;
		}

		for(int i = 0; i < 10; i++){
			cout << ans[i] << (i != 9 ? " " : "");
		}
		cout << endl;
	}


}
accuracy: 1
time_ms: 40
memory_kb: 3436
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define r(i,n) for(int i=0;i<n;i++)
typedef double D;
typedef complex<D> P;
typedef pair<P,P>L;
typedef vector<L> VP;
const D EPS = 1e-9;
#define fi first
#define se second
#define mk make_pair
#define X real()
#define Y imag()
#define LE(n,m) ((n) < (m) + EPS)
#define GE(n,m) ((n) + EPS > (m))
#define EQ(n,m) (abs((n)-(m)) < EPS)
D dot(P a, P b) {return (conj(a)*b).X; }
D 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;
  if (cross(b,c) < -EPS) return -1;
  if (dot(b,c)   < -EPS) return +2;
  if (norm(b) < norm(c)) return -2; 
  return 0;
}
bool isecLP(P a1, P a2, P b) {
  return abs(ccw(a1, a2, b)) != 1;
}
bool isecLL(P a1, P a2, P b1, P b2) {
  return !isecLP(a2-a1, b2-b1, 0) || isecLP(a1, b1, b2);
}
bool isecLS(P a1, P a2, P b1, P b2) {
  return cross(a2-a1, b1-a1) * cross(a2-a1, b2-a1) < EPS;
}
bool isecSS(P a1, P a2, P b1, P b2) {
  return ccw(a1, a2, b1)*ccw(a1, a2, b2) <= 0 &&
         ccw(b1, b2, a1)*ccw(b1, b2, a2) <= 0;
}
bool isecSP(P a1, P a2, P b) {
  return !ccw(a1, a2, b);
  // return abs(a1 - b) + abs(a2 - b) - abs(a2 - a1) < EPS;  //Perfective
}
double x3,x4,y3,y4;
VP v,t,x,cv,ch;
int n,a[10];
bool ch_dfs(int p){
  r(i,v.size())if(i!=p){
    if(v[p].first==v[i].first)return 1;
    if(v[p].first==v[i].second)return 1;
    if(v[p].second==v[i].first)return 1;
    if(v[p].second==v[i].second)return 1;
  }
  return 0;
}
void dfs(int d){
  r(i,cv.size()){
    r(j,v.size()){
      if(v[j].first==cv[i].first||v[j].first==cv[i].second||
         v[j].second==cv[i].first||v[j].second==cv[i].second){
        cv.push_back(v[j]);
        v.erase(v.begin()+j);
        j--;
        dfs(d+1);
        return ;
      }
    }
  }
  if(d==2){
    r(i,t.size()){
      r(j,cv.size()){
        if(isecSS(cv[j].fi,cv[j].se,t[i].fi,t[i].se)){
          t.erase(t.begin()+i);
          i--;
        }
      }
    }
    a[4]++;
  }
  else if(d==3){
    int flag=0;
    r(i,t.size()){
      r(j,cv.size()){
        if(isecSS(cv[j].fi,cv[j].se,t[i].fi,t[i].se)){
          t.erase(t.begin()+i);
          flag++;
          i--;
        }
      }
    }
    if(flag)a[3]++;
    else a[7]++;
  }
  else if(d==4){
    int flag=0;
    r(i,cv.size()){
      r(j,cv.size()){
        if(cv[i].first==cv[j].first) flag++;
        else if(cv[i].first==cv[j].second) flag++;
        else if(cv[i].second==cv[j].first) flag++;
        else if(cv[i].second==cv[j].second) flag++;
      }
    }
    if(flag==12){
      flag=0;
      r(i,t.size()){
        r(j,cv.size()){
          if(isecSS(cv[j].fi,cv[j].se,t[i].fi,t[i].se)){
            t.erase(t.begin()+i);
            flag++;
            i--;
          }
        }
      }
      if(flag) a[8]++;
      else a[0]++;
    }
    else a[9]++;
  }
  else{
    ch.clear();
    r(i,cv.size()){
      int f=0;
      r(j,cv.size()){
        if(i!=j){
          if(cv[i].first==cv[j].first) f++;
          else if(cv[i].first==cv[j].second) f++;
          else if(cv[i].second==cv[j].first) f++;
          else if(cv[i].second==cv[j].second) f++; 
        }
      }
      if(f==1){
        ch.push_back(cv[i]);
        cv.erase(cv.begin()+i);
        break;
      }
    }
    r(i,4){
      r(j,cv.size()){
        if(ch[i].first==cv[j].first||ch[i].first==cv[j].second||
           ch[i].second==cv[j].first||ch[i].second==cv[j].second){
          ch.push_back(cv[j]);
          cv.erase(cv.begin()+j);
          break;
        }
      }
    }
    if(isecSS(ch[0].fi,ch[0].se,ch[3].fi,ch[3].se)||isecSS(ch[1].fi,ch[1].se,ch[4].fi,ch[4].se)){
      a[6]++;
      return ;
    }
    int fl=0;
    P p;
    if(ch[0].first==ch[1].first)p=ch[1].second,fl++;
    else if(ch[0].first==ch[1].second)p=ch[1].first,fl++;
    if(fl){
      if(ccw(ch[0].second,ch[0].first,p)==-1)a[2]++;
      else a[5]++;
      return;
    }
    if(ch[0].second==ch[1].first)p=ch[1].second;
    else if(ch[0].second==ch[1].second) p=ch[1].first;
    if(ccw(ch[0].first,ch[0].second,p)==-1)a[2]++;
    else a[5]++;
  }
}
int main(){
  while(cin>>n,n){
    t.clear();
    memset(a,0,sizeof(a));
    r(i,n){
      cin>>x3>>y3>>x4>>y4;
      v.push_back(mk(P(x3,y3),P(x4,y4)));
    }
    r(i,(int)v.size()){
      if(!ch_dfs(i)){
        t.push_back(v[i]);
        v.erase(v.begin()+i);
        i--;
      }
    }
    while(!v.empty()){
      cv.clear();
      cv.push_back(v[0]);
      v.erase(v.begin());
      dfs(1);
    }
    a[1]=t.size();
    r(i,10){
      if(i)cout<<' ';
      cout<<a[i];
    }
    cout<<endl;
  }
}
accuracy: 1
time_ms: 10
memory_kb: 3332
final_rank: 9

code_snippet: #include <bits/stdc++.h>
 
#define _overload(_1,_2,_3,name,...) name
#define _rep(i,n) _range(i,0,n)
#define _range(i,a,b) for(int i=int(a);i<int(b);++i)
#define rep(...) _overload(__VA_ARGS__,_range,_rep,)(__VA_ARGS__)
 
#define _rrep(i,n) _rrange(i,n,0)
#define _rrange(i,a,b) for(int i=int(a)-1;i>=int(b);--i)
#define rrep(...) _overload(__VA_ARGS__,_rrange,_rrep,)(__VA_ARGS__)
 
#define _all(arg) begin(arg),end(arg)
#define uniq(arg) sort(_all(arg)),(arg).erase(unique(_all(arg)),end(arg))
#define getidx(ary,key) lower_bound(_all(arg),key)-begin(arg)
#define clr(a,b) memset((a),(b),sizeof(a))
#define bit(n) (1LL<<(n))
 
using namespace std;
 
template<class T>void reg(vector<T> &ary,const T &elem){ary.emplace_back(elem);}
template<class T>bool chmin(T &a, const T &b) {return (b<a)?(a=b,1):0;}
template<class T>bool chmax(T &a, const T &b) { return (a<b)?(a=b,1):0;}
 
using R=long double; // __float128
const R EPS = 1E-11; // [-1000:1000]->EPS=1e-8 [-10000:10000]->EPS=1e-7
const R INF = 1E40;
constexpr R PI = acos(R(-1));
inline int sgn(const R& r){ return (r > EPS) - (r < -EPS);}
inline int sgn(const R& a, const R &b){ return sgn(a-b); }
inline R sq(R x){return sqrt(max<R>(x,0.0));}
 
using P=complex<R>;
using VP=vector<P>;
using L=struct{P s,t;};
using VL=vector<L>;
using C=struct{P c;R r;};
using VC=vector<C>;
using vi=vector<int>;
 
constexpr P O = P(0,0);
istream& operator >> (istream& is,P& p){ R x,y;is >> x >> y; p=P(x,y); return is;}
ostream& operator << (ostream& os,P& p){ os << real(p) << " " << imag(p); return os;}
 
namespace std{
    bool operator <  (const P& a,const P& b){ return sgn(real(a-b))?real(a-b)<0:sgn(imag(a-b))<0;}
    bool operator == (const P& a,const P& b){ return sgn(real(a-b))==0 && sgn(imag(a-b))==0;}
}
 
inline bool cmp_x(const P& p,const P& q){return sgn(real(p-q))?real(p)<real(q):sgn(imag(p-q));}
inline bool cmp_y(const P& a, const P& b){return sgn(imag(a-b)) ? imag(a-b)<0 : sgn(real(a-b))<0;}
inline bool cmp_a(const P& a, const P& b){return sgn(arg(a)-arg(b)) ? arg(a)-arg(b)<0 : sgn(norm(a)-norm(b))<0;}
bool operator <  (const L& a,const L& b){ return a.s==b.s?a.t<b.t:a.s<b.s;}
bool operator == (const L& a,const L& b){ return a.s==b.s&&a.t==b.t;}
 
//?????? dot ?????? det
inline R dot(P o,P a,P b){a-=o,b-=o; return real(conj(a)*b);}
inline R det(P o,P a,P b){a-=o,b-=o; return imag(conj(a)*b);}
inline P vec(L l){return l.t-l.s;}
 
// ?°???± verify AOJ CGL_1_A
P proj(P o,P a,P b){ a-=o,b-=o; return a*real(b/a);}
P proj(L l,P p){l.t-=l.s,p-=l.s;return l.s+l.t*real(p/l.t);}
// ????°? verify AOJ CGL_1_B
P refl(L l,P p){ return R(2.0)*proj(l,p)-p;}
// CCW verify AOJ CGL_1_C
enum CCW{ LEFT = 1,RIGHT = 2,BACK = 4,FRONT = 8,ON = 16};
inline int ccw(P o,P a, P b) {//???a??¨???b???????????????????????????
    if (sgn(det(o,a,b)) > 0) return LEFT;    // counter clockwise
    if (sgn(det(o,a,b)) < 0) return RIGHT;   // clockwise
    if (sgn(dot(o,a,b)) < 0) return BACK;    // b--base--a on line
    if (sgn(norm(a-o)-norm(b-o)) < 0) return FRONT;   // base--a--b on line
    return ON;// base--b--a on line  a??¨b????????????????????????
}
 
// ?????´ ?????? verify AOJ CGL_2_A
bool vertical(L a, L b) {return sgn(dot(O,vec(a),vec(b)))==0;}
bool parallel(L a, L b) {return sgn(det(O,vec(a),vec(b)))==0;}

// ???????????????verify AOJ CGL_2_B ???????????????????????´??????1,????????´??????0
bool ill(L a,L b){ return parallel(a,b)==false;}
bool ils(L l,L s,int end=0){ return sgn(det(l.s,l.t,s.s)*det(l.s,l.t,s.t))<=-end;}
bool iss(L a,L b,int end=0){
    int s1=ccw(a.s,a.t,b.s)|ccw(a.s,a.t,b.t);
    int s2=ccw(b.s,b.t,a.s)|ccw(b.s,b.t,a.t);
    if(end) return (s1&s2)==(LEFT|RIGHT);
    return (s1|s2)&ON || (s1&s2)==(LEFT|RIGHT);
}

R dsp(L s,P p){
    if(sgn(dot(s.s,s.t,p))<=0) return abs(p-s.s);
    if(sgn(dot(s.t,s.s,p))<=0) return abs(p-s.t);
    return abs(det(s.s,s.t,p))/abs(s.t-s.s);
}

struct UnionFind {
    vector<int> data;
    UnionFind(int size) : data(size, -1) { }
    bool unionSet(int x, int y) {
        x = root(x); y = root(y);
        if (x != y) {
            if (data[y] < data[x]) swap(x, y);
            data[x] += data[y]; data[y] = x;
        }
        return x != y;
    }
    bool findSet(int x, int y) {
        return root(x) == root(y);
    }
    int root(int x) {
        return data[x] < 0 ? x : data[x] = root(data[x]);
    }
    int size(int x) {
        return -data[root(x)];
    }
};

inline bool share(L& a, L& b){
    return (a.s == b.s or a.s == b.t or a.t == b.s or a.t == b.t);
}

int check(VL& ls){
    int n = ls.size();

    if(n == 1) return 1;
    if(n == 3 or n == 4){
        int cnt = 0;
        rep(i, n){
            rep(j, i + 1, n){
                if(share(ls[i], ls[j])){
                    cnt++;
                }
            }
        }
        if(n == 3){
            if(cnt == 1) return 4;
            else if(cnt == 2) return 7;
            else assert(false);
        }
        if(n == 4){
            if(cnt == 2) return 3;
            else if(cnt == 3) return 9;
            else if(cnt == 4) return 0;
            else assert(false);
        }
    }
    if(n == 5){
        rep(i, n){
            bool ok = false;
            rep(j, n){
                if(j == i) continue;
                if(share(ls[i], ls[j])){
                    ok = true;
                    break;
                }
            }
            if(not ok) return 8;
        }

        P s;
        [&]{
            rep(i, n){
                for(P p : {ls[i].s, ls[i].t}){
                    bool ok = true;
                    rep(j, n){
                        if(j == i) continue;
                        if(dsp(ls[j], p) < EPS){
                            ok = false;
                            break;
                        }
                    }
                    if(ok){
                        s = p;
                        return;
                    }
                }
            }
        }();

        VP ps = {s};
        vi used(n);
        rep(loop, n){
            rep(i, n){
                if(used[i]) continue;
                if(ls[i].s == ps.back()){
                    ps.emplace_back(ls[i].t);
                    used[i] = true;
                    break;
                }
                if(ls[i].t == ps.back()){
                    ps.emplace_back(ls[i].s);
                    used[i] = true;
                    break;
                }
            }
        }
        vi dirs(4);
        rep(i, 4){
            dirs[i] = sgn(det(O, ps[i + 1] - ps[i], ps[i + 2] - ps[i + 1]));
        }
        if(dirs[0] == dirs[1] and dirs[1] == dirs[2] and dirs[2] == dirs[3]){
            return 6;
        }
        if(dirs[0] == 1 and dirs[1] == 1 and dirs[2] == -1 and dirs[3] == -1){
            return 5;
        }
        if(dirs[0] == -1 and dirs[1] == -1 and dirs[2] == 1 and dirs[3] == 1){
            return 2;
        }
        assert(false);
    }

    assert(false);
}

int main(void){
    cin.tie(0);
    ios::sync_with_stdio(false);

    for(int n; cin >> n, n;){
        VL ls(n);
        for(auto& e : ls) cin >> e.s >> e.t;

        UnionFind uf(n);
        rep(i, n){
            rep(j, i + 1, n){
                if(iss(ls[i], ls[j])){
                    uf.unionSet(i, j);
                }
            }
        }

        vi used(n);
        vi res(10);
        rep(i, n){
            if(used[i]) continue;

            VL cur;
            rep(j, i, n){
                if(uf.findSet(i, j)){
                    cur.emplace_back(ls[j]);
                    used[j] = true;
                }
            }

            res[check(cur)]++;
        }

        rep(i, 10){
            cout << (i ? " ":"") << res[i];
        }
        cout << endl;
    }

    return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 3348
final_rank: 15

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define X first
#define Y second
bool on(P p1,P p2,P p3){
  P v1=P(p2.X-p1.X,p2.Y-p1.Y),v2=P(p3.X-p1.X,p3.Y-p1.Y);
  if(v1.X*v2.X<0||v1.Y*v2.Y<0) return 0;
  if(!v1.X) return !v2.X&&abs(v2.Y)<abs(v1.Y);
  if(!v1.Y) return !v2.Y&&abs(v2.X)<abs(v1.X);
  if(v1.X*v1.X+v1.Y*v1.Y<v2.X*v2.X+v2.Y*v2.Y) return 0;
  return v1.X*v2.Y-v1.Y*v2.X==0;
}
int main(){
  int n;
  while(cin>>n,n){
    P ed[2][n];
    for(int i=0;i<n;i++)
      cin>>ed[0][i].X>>ed[0][i].Y>>ed[1][i].X>>ed[1][i].Y;
    vector<int> G[n],G2[n];
    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
	if(i==j) continue;
	bool f=0;
	for(int x=0;x<2;x++)
	  for(int y=0;y<2;y++)
	    f|=ed[x][i]==ed[y][j];
	if(f){
	  G[i].push_back(j);
	  continue;
	}
	for(int x=0;x<2;x++)
	  f|=on(ed[0][i],ed[1][i],ed[x][j]);
	if(f) G2[i].push_back(j),G2[j].push_back(i);
      }
    }
    int ans[10]={};
    bool used[n];
    memset(used,0,sizeof(used));
    for(int i=0;i<n;i++){
      if(used[i]) continue;
      int ec=0;
      map<P,int> mp;
      vector<int> v;
      queue<int> q;
      q.push(i);
      while(!q.empty()){
	int p=q.front();q.pop();
	if(used[p]) continue;
	used[p]=1;
	mp[ed[0][p]]++;
	mp[ed[1][p]]++;
	v.push_back(p);
	for(int u:G[p]) q.push(u);
	for(int u:G2[p]) q.push(u),ec++;
      }
      ec/=2;
      int m=v.size(),o=mp.size();
      if(m==1) ans[1]++;
      if(m==3){
	if(o==5) ans[4]++;
	if(o==4) ans[7]++;
      }
      if(m==4){
	if(o==4) ans[0]++;
	if(o==6) ans[3]++;
	if(o==5) ans[9]++;
      }
      if(m==5){
	if(ec==2) ans[8]++;
	if(ec==1) ans[6]++;
	if(ec==0){
	  int a,b,c,d;
	  for(int j=0;j<m;j++){
	    if(mp[ed[0][v[j]]]==1){
	      a=v[j];b=0;
	      break;
	    }
	    if(mp[ed[1][v[j]]]==1){
	      a=v[j];b=1;
	      break;
	    }
	  }
	  for(int j=0;j<m;j++){
	    if(a==v[j]) continue; 
	    if(ed[!b][a]==ed[0][v[j]]){
	      c=v[j];d=1;
	      break;
	    }
	    if(ed[!b][a]==ed[1][v[j]]){
	      c=v[j];d=0;
	      break;
	    }
	  }
	  P v1=P(ed[b][a].X-ed[!b][a].X,ed[b][a].Y-ed[!b][a].Y);
	  P v2=P(ed[d][c].X-ed[!d][c].X,ed[d][c].Y-ed[!d][c].Y);
	  
	  if(v1.X*v2.Y-v1.Y*v2.X>0) ans[2]++;
	  else ans[5]++;
	}
      }
    }
    for(int i=0;i<10;i++) cout<<ans[i]<<" \n"[i==9];
  }
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 3104
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define FOR(i,k,n) for(int i = (int)(k); i < (int)(n); i++)
#define REP(i,n) FOR(i,0,n)
#define ALL(a) a.begin(), a.end()
#define MS(m,v) memset(m,v,sizeof(m))
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef vector<string> vs;
typedef pair<int, int> pii;
const int MOD = 1000000007;
const int INF = MOD + 1;
const ld EPS = 1e-12;
template<class T> T &chmin(T &a, const T &b) { return a = min(a, b); }
template<class T> T &chmax(T &a, const T &b) { return a = max(a, b); }

/*--------------------template--------------------*/

typedef long double ld;
const ld PI = acos(-1.0);
bool eq(ld a, ld b) { return abs(a - b) < EPS; }
typedef complex<ld> Point;
typedef vector<Point> Polygon;

namespace std
{
	bool operator < (const Point& a, const Point& b)
	{
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
}

struct Line
{
	Point a, b;
	Line() {};
	Line(Point p, Point q) :a(p), b(q) {};
	Line(ld x1, ld y1, ld x2, ld y2) :a(Point(x1, y1)), b(Point(x2, y2)) {};
};

ld dot(Point a, Point b)
{
	return real(conj(a)*b);
}

ld cross(Point a, Point b)
{
	return imag(conj(a)*b);
}

int ccw(Point a, Point b, Point c)
{
	b -= a; c -= a;
	if (cross(b, c) > EPS) return 1;    //counter cloclwise
	if (cross(b, c) < -EPS) return -1;  //cloclwise
	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;                           //a--c--b on line
}

bool isis_ss(Line s, Line t)
{
	return (ccw(s.a, s.b, t.a)*ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a)*ccw(t.a, t.b, s.b) <= 0);
}

bool isis_sp(Line s, Point p)
{
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a)) < EPS;
}

int label(Line s, vector<Line> segments)
{
	int edge = 0, mid = 0;
	for (auto i : segments)
	{
		if (((s.a == i.a) && (s.b == i.b)) || !isis_ss(s, i)) continue;
		if (s.a == i.a || s.a == i.b || s.b == i.a || s.b == i.b) edge++;
		else if (isis_sp(i, s.a) || isis_sp(i, s.b)) mid++;
	}
	if (edge == 2 && mid == 0) return 0;
	if (edge == 0 && mid == 0) return 1;
	if (edge == 1 && mid == 0) return 2;
	if (edge == 0 && mid == 1) return 3;
	if (edge == 1 && mid == 1) return 4;
	if (edge == 0 && mid == 2) return 5;
	assert(false);
}

int ident(vi v)
{
	vector<vi> lis(10);
	lis[0] = { 4,0,0,0,0,0 };
	lis[1] = { 0,1,0,0,0,0 };
	lis[2] = { 3,0,2,0,0,0 };
	lis[3] = { 1,0,2,1,0,0 };
	lis[4] = { 0,1,1,0,1,0 };
	lis[5] = { 3,0,2,0,0,0 };
	lis[6] = { 3,0,1,0,1,0 };
	lis[7] = { 1,0,2,0,0,0 };
	lis[8] = { 4,0,0,0,0,1 };
	lis[9] = { 2,0,1,0,1,0 };
	REP(i, 10)
	{
		if (v == lis[i]) return i;
	}
	assert(false);
}

int main()
{
	cin.sync_with_stdio(false); cout << fixed << setprecision(10);
	int n;
	while (cin >> n, n)
	{
		vector<Line> seg;
		REP(i, n)
		{
			ld a, b, c, d;
			cin >> a >> b >> c >> d;
			seg.emplace_back(a, b, c, d);
		}
		vector<vi> g(n);
		REP(i, n)REP(j, n)
		{
			if (i == j) continue;
			if (isis_ss(seg[i], seg[j]))
			{
				g[i].push_back(j);
				g[j].push_back(i);
			}
		}
		vector<vi> group;
		vector<bool> vis(n);
		REP(i, n)
		{
			if (vis[i]) continue;
			vi tmp;
			vis[i] = true;
			queue<int> que;
			que.push(i);
			tmp.push_back(i);
			while (!que.empty())
			{
				int t = que.front();
				que.pop();
				for (auto j : g[t])
				{
					if (vis[j]) continue;
					vis[j] = true;
					que.push(j);
					tmp.push_back(j);
				}
			}
			group.push_back(tmp);
		}
		vi ans(10);
		for (auto i : group)
		{
			vector<Line> segments;
			for (auto j : i) segments.push_back(seg[j]);
			vi types(6);
			for (auto j : segments)
			{
				int t = label(j, segments);
				types[t]++;
			}
			int res = ident(types);
			if (res == 2)
			{
				Line a, b;
				for (auto j : segments)
				{
					if (label(j, segments) == 2) a = j;
				}
				for (auto j : segments)
				{
					if ((a.a == j.a) && (a.b == j.b)) continue;
					if (isis_ss(a, j)) b = j;
				}
				Point p, q, r;
				if (a.a == b.a)
				{
					p = a.b, q = a.a, r = b.b;
				}
				if (a.a == b.b)
				{
					p = a.b, q = a.a, r = b.a;
				}
				if (a.b == b.a)
				{
					p = a.a, q = a.b, r = b.b;
				}
				if (a.b == b.b)
				{
					p = a.a, q = a.b, r = b.a;
				}
				if (ccw(p, q, r) == 1) res = 5;
				else if (ccw(p, q, r) == -1) res = 2;
			}
			ans[res]++;
		}
		REP(i, 10) cout << ans[i] << (i == 9 ? "\n" : " ");
	}
	return 0;
}
accuracy: 1
time_ms: 320
memory_kb: 3468
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long LL;
typedef pair<LL, LL> PLL;

#define ALL(a)  (a).begin(),(a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define SZ(a) int((a).size())
#define EACH(i,c) for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); ++i)
#define EXIST(s,e) ((s).find(e)!=(s).end())
#define SORT(c) sort((c).begin(),(c).end())

#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n)  FOR(i,0,n)

#define FF first
#define SS second
template<class S, class T>
istream& operator>>(istream& is, pair<S,T>& p){
  return is >> p.FF >> p.SS;
}

const double EPS = 1e-10;
const double PI  = acos(-1.0);
const LL MOD = 1e9+7;

using Seg = pair<PII,PII>;
int dot(PII p1, PII p2){
  return p1.FF * p2.FF + p1.SS * p2.SS;
}
int cross(PII p1, PII p2){
  return p1.FF * p2.SS - p1.SS * p2.FF;
}
PII operator-(const PII& l, const PII& r){
  return PII(l.FF - r.FF, l.SS - r.SS);
}
  
bool isp(Seg s1, Seg s2){
  return s1.FF == s2.FF || s1.FF == s2.SS || s1.SS == s2.FF || s1.SS == s2.SS;
}
bool on(PII p, Seg s){
  return p != s.FF && p != s.SS && cross(s.FF-p, s.SS-p) == 0 && dot(s.FF-p, s.SS-p) < 0;
}
bool ist(Seg s1, Seg s2){
  return on(s1.FF, s2) || on(s1.SS, s2) || on(s2.FF, s1) || on(s2.SS, s1);
}

void dfs(int u, VVI& ps, VVI& ts, vector<bool>& use, PII& res, VI& buf){
  buf.PB(u);
  use[u] = true;
  for(int v: ps[u]){
	++res.FF;
	if(!use[v])
	  dfs(v, ps, ts, use, res, buf);
  }
  for(int v: ts[u]){
	++res.SS;
	if(!use[v])
	  dfs(v, ps, ts, use, res, buf);
  }
}

bool istwo(Seg s1, Seg s2){
  if(s1.SS != s2.FF) swap(s1.FF, s1.SS);
  if(s1.SS != s2.FF) swap(s2.FF, s2.SS);
  if(s1.SS != s2.FF) swap(s1.FF, s1.SS);
  return cross(s1.SS-s1.FF, s2.SS-s2.FF) < 0;
}

int main(){
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  int N;
  while(cin>>N,N){
	vector<Seg> ss(N);
	REP(i,N) cin >> ss[i];

	VVI isps(N), ists(N);
	REP(i,N) REP(j,i){
	  if(isp(ss[i], ss[j])){
		isps[i].PB(j);
		isps[j].PB(i);
	  }
	  else if(ist(ss[i], ss[j])){
		ists[i].PB(j);
		ists[j].PB(i);
	  }
	}

	vector<bool> use(N);
	VI ans(10);
	REP(i,N){
	  if(use[i]) continue;
	  VI buf;
	  PII tmp;
	  dfs(i, isps, ists, use, tmp, buf);
	  tmp.FF /= 2;
	  tmp.SS /= 2;
// 0 1 2 3 4 5 6 7 8 9
//lines:
// 4 1 5 4 3 5 5 3 5 4
//points:
// 4 0 4 2 1 4 4 2 4 3
//touching:
// 0 0 0 1 1 0 1 0 2 1
	  switch(SZ(buf)){
	  case 1:
		ans[1]++; break;
	  case 3:
		ans[(tmp.FF==1?4:7)]++; break;
	  case 4:
		if(tmp.FF==4) ans[0]++;
		else if(tmp.FF==2) ans[3]++;
		else ans[9]++;
		break;
	  case 5:
		if(tmp.SS==1) ans[6]++;
		else if(tmp.SS==2) ans[8]++;
		else{
		  int e1 = -1;
		  for(int x:buf) if(SZ(isps[x]) == 1) e1 = x;
		  int e2 = isps[e1][0];
		  ans[(istwo(ss[e1], ss[e2])?2:5)]++;
		}
		break;
	  }
	}

	REP(i,10) cout << (i?" ":"") << ans[i]; cout << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3224
final_rank: 6

code_snippet: #include<bits/stdc++.h>
using namespace std;


typedef complex<double> P; //Point
typedef pair<P,P> L; //Line, Segment

const double EPS = 1e-8;
const double PI = 6.0 * asin(0.5);

namespace std {
  bool operator < (const P& a, const P& b){
    return fabs(real(a)-real(b)) < EPS ? imag(a) < imag(b) : real(a) < real(b);
  }
  bool operator == (const P&a , const P& b) {
    return abs(a-b)<EPS;
  }  
}

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

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; // c -- a -- b テ」ツ?ョテ、ツクツ?ァツ崢エテァツキツ?
  if(norm(b) < norm(c)) return -2; // a -- b -- c テ」ツ?ョテ、ツクツ?ァツ崢エテァツキツ?
  return 0; // a -- c -- b テ」ツ?ョテ、ツクツ?ァツ崢エテァツキツ?
}

bool isIntersect(L s1, L s2){ 
  if(max(real(s1.first), real(s1.second)) + EPS < min(real(s2.first), real(s2.second)) ||
     max(imag(s1.first), imag(s1.second)) + EPS < min(imag(s2.first), imag(s2.second)) ||
     max(real(s2.first), real(s2.second)) + EPS < min(real(s1.first), real(s1.second)) ||
     max(imag(s2.first), imag(s2.second)) + EPS < min(imag(s1.first), imag(s1.second))) return false;

  return ( ccw(s1.first,s1.second,s2.first) * ccw(s1.first,s1.second,s2.second) <= 0 &&
           ccw(s2.first,s2.second,s1.first) * ccw(s2.first,s2.second,s1.second) <= 0 );
}

P crossPoint(L l, L m){
  double A = cross(l.second - l.first, m.second - m.first);
  double B = cross(l.second - l.first, l.second - m.first);
  if(fabs(A) < EPS && fabs(B) < EPS) return m.first;
  else if(fabs(A) >= EPS) return m.first + B / A * (m.second - m.first);
}

vector<int> G[1111];
bool used[1111];

void dfs(int id,vector<int> &v){
  if( used[id] ) return;
  used[id] = true;
  for( int to : G[id] ) dfs( to, v );
  v.push_back( id );
}



bool zorq(const vector<int> &v,const vector<L>& ss){
  for(int i : v ){
    for(int j : v ){
      if( i == j ) continue;
      if( isIntersect( ss[i], ss[j] )  ){
        P p = crossPoint( ss[i], ss[j] );        
        if( p != ss[i].first && p != ss[i].second ) return true;
      }
    }
  }
  return false;
}

int torf(const vector<int> &v, const vector<L>& ss ){
  for( int i : v ){
    if( G[i].size() == 1 ){
      int to = G[i][0];
      int nx = G[to][0];
      if( nx == i ) nx = G[to][1];

      P p1 = ss[i].first;
      P p2 = crossPoint( ss[i], ss[to] );
      P p3 = crossPoint( ss[to],ss[nx] );
      if( p1 == p2 ) p1 = ss[i].second;
      if( ccw( p1, p2, p3 ) == 1 ) return 5;
      else return 2;
    }
  }
  return -1;
}

int num(int id,const vector<L>& ss){
  vector<int> v;
  dfs( id, v );

  if( v.size() == 1 ) return 1;
  int sum[11]={};
  for( int i : v ){
    sum[G[i].size()]++;
  }

  if( sum[1] == 3 && sum[3] == 1 ) return 3;
  if( sum[1] == 1 && sum[2] == 3 && sum[3] == 1 ) return 6;
  if( sum[2] == 3 && sum[3] == 2 ) return 8;
  if( sum[2] == 4 ) {
    // 0 or 9
    if( zorq( v, ss ) ) return 9;
    return 0;
  }
  if( sum[1] == 2 && sum[2] == 1 ) {
    // 7 or 4
    if( zorq( v, ss ) ) return 4;
    return 7;
  }
  return torf(v,ss);
  
  
}

int main(){
  int n;
  while( cin >> n && n ){
    vector<L> s;
    for(int i=0;i<n;i++) G[i].clear();
    memset( used,0,sizeof(used) );
    
    for(int i=0;i<n;i++){
      int x,y,x2,y2; cin>> x >>y >> x2 >> y2;
      s.push_back( L( P(x,y) , P(x2,y2) ) );      
    }

    for(int i=0;i<n;i++){
      for(int j=0;j<n;j++){
        if( i==j ) continue;
        if( isIntersect( s[i], s[j] ) ) {
          G[i].push_back( j );
        }
      }
    }
    

    int res[11]={};
    for(int i=0;i<n;i++){
      if( used[i] ) continue;
      int st = num(i,s) ;
      res[st]++;
    }
    for(int i=0;i<10;i++) {
      if( i ) cout << " ";
      cout << res[i];
    }
    cout << endl;
    
  }
}
accuracy: 1
time_ms: 40
memory_kb: 3244
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define MAX_N 1005
typedef complex<double> P;
double eps=1e-6;

P calc(P a,P b,P c,P d){
  a-=d;b-=d;c-=d;
  return d+a+(b-a)*imag(a/c)/imag(a/c-b/c);
}

bool isParallel(P a,P b,P c,P d){
  return ( abs( imag( (a-b)*conj(c-d) ) ) < eps );
}

bool eq(P a,P b){
  return ( abs(a-b) < eps );
}

int n;
P A[MAX_N],B[MAX_N];
int G[MAX_N][MAX_N];
int ans[10];
bool visited[MAX_N];
vector<int> vec;

int solve(){
  if(vec.size()==1)return 1;
  int cnt1=0,cnt2=0,size=vec.size();
  for(int i=0;i<size;i++){
    for(int j=0;j<i;j++){
      if(G[vec[i]][vec[j]]==1)cnt1++;
      if(G[vec[i]][vec[j]]==2)cnt2++;
    }
  }

  //  cout<<cnt1<<' '<<cnt2<<' '<<size<<endl;
  P g= A[vec[0]];
  for(int i=0;i<size;i++){
    int id=vec[i];
    //    cout<<A[id]-g<<' '<<B[id]-g<<endl;
  }
  if(size==3){
    if(cnt1==2&&cnt2==0)return 7;
    return 4;
    
    //    if(cnt1==1&&cnt2==1)return 4;
    //    assert(0);
  }
  if(size==4){
    if(cnt1==4&&cnt2==0)return 0;
    if(cnt1==3&&cnt2==1)return 9;
    if(cnt1==2&&cnt2==1)return 3;
    return 3;
    //    assert(0);
  }
  if(size==5){
    if(cnt1==4&&cnt2==1)return 6;
    if(cnt1==4&&cnt2==2)return 8;
    if(cnt1==4&&cnt2==0){
      for(int i=0;i<size;i++){
        int C=0,D;
        for(int j=0;j<size;j++){
          if(i!=j&&G[vec[i]][vec[j]]){
            C++;
            D=j;
          }
        }
        

        if(C==1){
          P cp=calc(A[vec[i]],B[vec[i]],A[vec[D]],B[vec[D]]);

          P from,to,prev;
          if(eq(cp,A[vec[i]]))prev=B[vec[i]],from=A[vec[i]];
          else if(eq(cp,B[vec[i]]))prev=A[vec[i]],from=B[vec[i]];
          //else assert(0);
          
          if(eq(cp,A[vec[D]]))to=B[vec[D]];
          else if(eq(cp,B[vec[D]]))to=A[vec[D]];
          //          else assert(0);

          P base=from-prev,target=to-prev;
          if( imag(target*conj(base)) < -eps )return 2;
          else if( imag(target*conj(base)) >  eps )return 5;
          //          else assert(0);
        }
      }
    }
    return 2;
    assert(0);
  }
  return -1;
}

void dfs(int pos){
  if(visited[pos])return;
  visited[pos]=true;
  vec.push_back(pos);
  for(int i=0;i<n;i++)
    if(G[pos][i]!=0)dfs(i);
}
bool eq(double a,double b){
  return (-eps < a-b && a-b < eps );
}
bool onSegment(P a,P b,P c){
  return eq( abs(a-b) , abs(a-c) + abs(b-c) );
}

int check(int si,int ti){
  if( isParallel(A[si],B[si],A[ti],B[ti]) )return 0;
  P k=calc(A[si],B[si],A[ti],B[ti]);
  int count=3;
  if( eq(k,A[si]) || eq(k,B[si]) )count--;
  if( eq(k,A[ti]) || eq(k,B[ti]) )count--;
  if( onSegment(A[si],B[si],k) && onSegment(A[ti],B[ti],k) )return count;
  return 0;
}

int main(){
  while(1){
    cin>>n;
    if(n==0)break;
    memset(G,0,sizeof(G));
    for(int i=0;i<n;i++){
      double ax,ay,bx,by;
      cin>>ax>>ay>>bx>>by;
      A[i]=P(ax,ay);
      B[i]=P(bx,by);
      for(int j=0;j<i;j++){
        G[i][j]=G[j][i]=check(i,j);
      }
    }
    memset(ans,0,sizeof(ans));
    memset(visited,false,sizeof(visited));
    for(int i=0;i<n;i++){
      if(visited[i])continue;
      vec.clear();
      dfs(i);
      
      ans[ solve() ]++;
    }
    for(int i=0;i<10;i++){
      if(i)cout<<' ';
      cout<<ans[i];
    }
    cout<<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 5256
final_rank: 17