#include <cstdio>
#include <vector>
#include <algorithm>
#include <utility>
#include <complex>
#include <cmath>
#include <cfloat>
#include <cstdlib>
using namespace std;

#define EPS 1e-9

typedef complex<double> P;
typedef const P &rP;
typedef vector<P> vP;
typedef vector<int> vint;

struct segment{
	P a, b;
	segment(){}
	segment(rP a, rP b): a(a), b(b) {}
};

struct coninfo{
	int bnum, pnum;
	double arg;

	coninfo(int p): pnum(p), bnum(-1), arg(0.0) {}

	bool operator< (const coninfo &c) const{
		return arg < c.arg;
	}
};

inline bool eq(double a, double b){
	return abs(a - b) < EPS;
}

namespace std{
	bool operator< (rP a, rP b){
		if(!eq(real(a), real(b))){
			return real(a) < real(b);
		}
		if(!eq(imag(a), imag(b))){
			return imag(a) < imag(b);
		}
		return false;
	}
}

double dot(rP va, rP vb){
	return real(va) * real(vb) + imag(va) * imag(vb);
}

double cross(rP va, rP vb){
	return real(va) * imag(vb) - imag(va) * real(vb);
}

int ccw(rP 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;
}

P intrSS(const segment &s, const segment &t){
	P dSab = s.b - s.a;
	P dTba = t.a - t.b;
	P dSTa = t.a - s.a;

	double D = cross(dSab, dTba);

	if(abs(D) > EPS){
		double p = cross(dSTa, dTba) / D;
		double q = cross(dSab, dSTa) / D;

		if(-EPS < p && p < 1.0 + EPS && -EPS < q && q < 1.0 + EPS){
			return s.a + p * dSab;
		}
	}
	return P(DBL_MAX, DBL_MAX);
}


bool intersectSP(const segment &s, rP p){
	return eq(abs(s.a - p) + abs(s.b - p), abs(s.a - s.b));
}

bool merge_if_able(segment &s, const segment &t) {
	if(abs(cross(s.b-s.a, t.b-t.a)) > EPS)
		return false;

	if(ccw(s.a, t.a, s.b) == +1 || ccw(s.a, t.a, s.b) == -1)
		return false; // not on the same line

	if(ccw(s.a, s.b, t.a) == -2 || ccw(t.a, t.b, s.a) == -2)
		return false; // separated

	s = segment(min(s.a, t.a), max(s.b, t.b));
	return true;
}

void merge_segments(vector<segment>& segs) {
	for (int i = 0; i < segs.size(); ++i)
		if (segs[i].b < segs[i].a)
			swap(segs[i].b, segs[i].a);

	for (int i = 0; i < segs.size(); ){
		int inc = 1;
		for (int j = i+1; j < segs.size(); ++j){
			if (merge_if_able(segs[i], segs[j])){
				segs[j--] = segs.back();
				segs.pop_back();
				inc = 0;
			}
		}
		
		i += inc;
	}
}

void segarrange(const vector<segment> &ss, vector<P> &ps, vector<vector<coninfo> > &ret){
	for (int i = 0; i < ss.size(); ++i) { // O(n^2)
		ps.push_back( ss[i].a );
		ps.push_back( ss[i].b );
		for (int j = i+1; j < ss.size(); ++j){
			P intr = intrSS(ss[i], ss[j]);
			if(real(intr) < DBL_MAX){
				ps.push_back(intr);
			}
		}
	}

	sort(ps.begin(), ps.end());
	ps.erase(unique(ps.begin(), ps.end()), ps.end());

	vector<vector<coninfo> > g(ps.size());
	for (int i = 0; i < ss.size(); ++i) {
		vector< pair<double, int> > list;
		for (int j = 0; j < ps.size(); ++j)
			if (intersectSP(ss[i], ps[j]))
				list.push_back(make_pair(norm(ss[i].a-ps[j]), j));

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

		for (int j = 0; j+1 < list.size(); ++j) {
			int a = list[j].second, b = list[j+1].second;
			g[a].push_back(coninfo(b));
			g[b].push_back(coninfo(a));
		}
	}

	g.swap(ret);
}

double distance_ls_p(rP a, rP b, rP c){
	if( dot(b - a, c - a) <= 0.0 ) return abs(c - a);
	if( dot(a - b, c - b) <= 0.0 ) return abs(c - b);
	return abs(cross(b - a, c - a)) / abs(b - a);
}

bool contains(const vector<P> &plg, rP pt){
	int cnt = 0;
	double y = imag(pt);

	for(int i = 0; i + 1 < plg.size(); ++i){
		int j = i + 1;

		if(distance_ls_p(plg[i], plg[j], pt) < EPS){
			return true;
		}

		double dyi = imag(plg[i]) - y;
		double dyj = y - imag(plg[j]);
		double tx = (dyi * real(plg[j]) + dyj * real(plg[i])) / (dyi + dyj);

		if(imag(plg[i]) >= y && imag(plg[j]) < y){
			if( tx < real(pt) ) ++cnt;
		}
		else if(imag(plg[i]) < y && imag(plg[j]) >= y){
			if( tx < real(pt) ) ++cnt;
		}
	}
	
	return (cnt % 2 != 0);
}

P inner(const vector<P> &plg){
	int n = plg.size() - 1;

	for(int i = 0; ; ++i){
		int j = (i + 1) % n;
		int k = (i + 2) % n;

		P cen = (plg[i] + plg[j] + plg[k]) / 3.0;
		if(contains(plg, cen)) return cen;
	}
}



vector<vector<P> > plgs;
vector<P> pnts;
vector<vector<P> > blocks;
vector<vector<coninfo> > cons;
vector<vint> WF;
int out;

void prepare(){
	vector<segment> segs;
	segs.reserve(35);
	blocks.reserve(1000);
	for(int i = 0; i < plgs.size(); ++i){
		for(int j = 1; j < plgs[i].size(); ++j){
			segs.push_back(segment(plgs[i][j-1], plgs[i][j]));
		}

		if(i > 0){
			segs.push_back(segment(plgs[i-1][0], plgs[i][0]));
		}
	}

	merge_segments(segs);
	segarrange(segs, pnts, cons);

	for(int i = 0; i < cons.size(); ++i){
		for(int j = 0; j < cons[i].size(); ++j){
			cons[i][j].arg = arg(pnts[cons[i][j].pnum] - pnts[i]);
		}
		sort(cons[i].begin(), cons[i].end());
	}

	for(int i = 0; i < cons.size(); ++i){
		for(int j = 0; j < cons[i].size(); ++j){
			if(cons[i][j].bnum != -1) continue;

			int p = i, idx = j;
			vector<P> blk;
			while(1){
				blk.push_back(pnts[p]);
				int nxtp = cons[p][idx].pnum;
				int nxti;
				for(nxti = 0; cons[nxtp][nxti].pnum != p; ++nxti);

				--nxti;
				if(nxti < 0) nxti += cons[nxtp].size();

				if(cons[nxtp][nxti].bnum != -1){
					break;
				}

				cons[nxtp][nxti].bnum = blocks.size();
				p = nxtp;
				idx = nxti;
			}

			double S = 0.0;
			for(int k = 1; k < blk.size(); ++k){
				S += cross(blk[k-1], blk[k]);
			}
			if(S < -EPS){
				out = blocks.size();
			}

			blocks.push_back(blk);
		}
	}

	vint gas(blocks.size());
	for(int i = 0; i < blocks.size(); ++i){
		if(i == out) continue;

		P cen = inner(blocks[i]);
		for(int j = 0; j < plgs.size(); ++j){
			if(contains(plgs[j], cen)){
				++gas[i];
			}
		}
	}

	WF.assign(blocks.size(), vint(blocks.size(), 1000000000));
	for(int i = 0; i < blocks.size(); ++i){
		WF[i][i] = 0;
	}
	for(int i = 0; i < cons.size(); ++i){
		int k = cons[i].size() - 1;
		for(int j = 0; j < cons[i].size(); ++j){
			int a = cons[i][k].bnum, b = cons[i][j].bnum;
			WF[a][b] = WF[b][a] = abs(gas[b] - gas[a]);
			k = j;
		}
	}

	for(int k = 0; k < blocks.size(); ++k)
	for(int i = 0; i < blocks.size(); ++i)
	for(int j = 0; j < i; ++j){
		WF[i][j] = WF[j][i] = min(WF[i][j], WF[i][k] + WF[k][j]);
	}
}

int blocknumber(rP p){
	for(int i = 0; i < blocks.size(); ++i){
		if(i != out && contains(blocks[i], p)){
			return i;
		}
	}
	return out;
}

int query(P pfrom, P pto){
	int from = blocknumber(pfrom), to = blocknumber(pto);
	return WF[from][to];
}


int main(){
	int n, m, q, x, y, x2, y2;
	scanf("%d", &n);

	plgs.resize(n);
	for(int i = 0; i < n; ++i){
		scanf("%d", &m);
		plgs[i].resize(m + 1);
		for(int j = 0; j < m; ++j){
			scanf("%d%d", &x, &y);
			plgs[i][j] = P(x, y);
		}
		plgs[i][m] = plgs[i][0];
	}

	prepare();

	scanf("%d", &q);
	for(int i = 0; i < q; ++i){
		scanf("%d%d%d%d", &x, &y, &x2, &y2);
		printf("%d\n", query(P(x, y), P(x2, y2)));
	}
}

Measured memory_bytes: 1236