#include<cmath>
#include<cstdio>
#include<vector>
#include<cassert>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const double EPS=1e-8;
const double PI=acos(-1);

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	point operator+(const point &a)const{ return point(x+a.x,y+a.y); }
	point operator-(const point &a)const{ return point(x-a.x,y-a.y); }
	point operator/(double c)const{ return point(x/c,y/c); }
	bool operator< (const point &a)const{ return x+EPS<a.x || abs(x-a.x)<EPS && y+EPS<a.y; }
	bool operator==(const point &a)const{ return abs(x-a.x)<EPS && abs(y-a.y)<EPS; }
	bool operator!=(const point &a)const{ return abs(x-a.x)>EPS || abs(y-a.y)>EPS; }
};

point operator*(double c,const point &a){ return point(c*a.x,c*a.y); }

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

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

double abs(const point &a){ return sqrt(a.x*a.x+a.y*a.y); }

double arg(const point &a){
	double t=atan2(a.y,a.x);
	return t<0?t+2*PI:t;
}

struct segment{
	point a,b;
	segment(){}
	segment(const point &a,const point &b):a(a),b(b){}
};

typedef vector<point> polygon;

enum{CCW=1,CW=-1,ON=0};
int ccw(const point &a,const point &b,const point &c){
	double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

bool is_ccw(const polygon &F){
	int n=F.size();
	double A=0;
	rep(i,n) A+=cross(F[i],F[(i+1)%n]);
	return A>-EPS;
}

bool intersect(const segment &S1,const segment &S2){
	if(max(S1.a.x,S1.b.x)+EPS<min(S2.a.x,S2.b.x)
	|| max(S1.a.y,S1.b.y)+EPS<min(S2.a.y,S2.b.y)
	|| max(S2.a.x,S2.b.x)+EPS<min(S1.a.x,S1.b.x)
	|| max(S2.a.y,S2.b.y)+EPS<min(S1.a.y,S1.b.y)) return false;
	return ccw(S1.a,S1.b,S2.a)*ccw(S1.a,S1.b,S2.b)<=0
		&& ccw(S2.a,S2.b,S1.a)*ccw(S2.a,S2.b,S1.b)<=0;
}

bool cover(const segment &S,const point &p){
	return abs(cross(S.a-p,S.b-p))<EPS && dot(S.a-p,S.b-p)<EPS;
}

point get_intersect(const segment &S1,const segment &S2){
	double a1=cross(S1.b-S1.a,S2.b-S2.a);
	double a2=cross(S1.b-S1.a,S1.b-S2.a);
	if(abs(a1)<EPS){
		if(cover(S1,S2.a)) return S2.a;
		if(cover(S1,S2.b)) return S2.b;
		if(cover(S2,S1.a)) return S1.a;
		return S1.b;
	}
	return S2.a+a2/a1*(S2.b-S2.a);
}

bool cover(const polygon &F,const point &p){
	int n=F.size();
	bool res=false;
	rep(i,n){
		point v1=F[i]-p,v2=F[(i+1)%n]-p;
		if(v1.y>v2.y) swap(v1,v2);
		if(v1.y<EPS && EPS<v2.y && cross(v1,v2)>EPS) res=!res;
		if(abs(cross(v1,v2))<EPS && dot(v1,v2)<EPS) return true;
	}
	return res;
}

bool cover(const polygon &F,const polygon &G){
	int m=F.size(),n=G.size();
	rep(i,n){
		if(!cover(F,G[i])) return false;

		segment S(G[i],G[(i+1)%n]);

		vector<point> Q; // G の辺 i と F との交点全体
		Q.push_back(S.a);
		Q.push_back(S.b);
		rep(j,m){
			segment T(G[j],G[(j+1)%m]);
			if(intersect(S,T)){
				Q.push_back(get_intersect(S,T));
			}
		}
		sort(Q.begin(),Q.end());

		rep(j,(int)Q.size()-1) if(!cover(F,(Q[j]+Q[j+1])/2)) return false;
	}

	return true;
}

void arrangement(const vector<segment> &S,vector<point> &P,vector<int> *G){
	int n=S.size();
	P.clear();
	rep(i,n){
		P.push_back(S[i].a);
		P.push_back(S[i].b);
		rep(j,i) if(intersect(S[i],S[j])) P.push_back(get_intersect(S[i],S[j]));
	}
	sort(P.begin(),P.end());
	P.erase(unique(P.begin(),P.end()),P.end());

	rep(u,P.size()) G[u].clear();
	rep(i,n){
		vector<int> on;
		rep(u,P.size()) if(cover(S[i],P[u])) on.push_back(u);
		rep(j,(int)on.size()-1){
			int u=on[j],v=on[j+1];
			G[u].push_back(v);
			G[v].push_back(u);
		}
	}
}

const int INF=1<<29;

int main(){
	int n; scanf("%d",&n);
	polygon F[6];
	rep(i,n){
		int m; scanf("%d",&m);
		F[i].resize(m);
		rep(j,m) scanf("%lf%lf",&F[i][j].x,&F[i][j].y);
	}
	{
		F[n].push_back(point(-2000,-2000));
		F[n].push_back(point( 2000,-2000));
		F[n].push_back(point( 2000, 2000));
		F[n].push_back(point(-2000, 2000));
		n++;
	}
	vector<segment> S;
	rep(i,n) rep(j,F[i].size()) S.push_back(segment(F[i][j],F[i][(j+1)%F[i].size()]));

	vector<point> P;
	vector<int> G[700];
	arrangement(S,P,G);

	vector<polygon> Q; // F[0..n-1] を分割した多角形たち ( 穴は無視する. つまり Q1 \in Q2 なら単に Q1, Q2 の両方が Q に含まれる )
	// calculate Q
	static bool used[700][700]; // used[u][v] := ( 辺 u->v を使った )
	rep(u,P.size()) rep(i,G[u].size()) {
		int v=G[u][i];
		if(used[u][v]) continue;

		used[u][v]=true;
		polygon H(1,P[u]);
		// trace
		{
			int tmp=u;

			int u0=u;
			while(v!=u0){
				int v_next=-1;
				double phi=arg(P[u]-P[v]),phi0,d0;
				rep(j,G[v].size()){
					int w=G[v][j];
					if(w!=u){
						double phi1=arg(P[w]-P[v]),d1=abs(P[w]-P[v]);
						if(phi1<phi) phi1+=2*PI;
						if(v_next==-1 || phi0<phi1 || abs(phi0-phi1)<EPS && d0>d1) v_next=w, phi0=phi1, d0=d1;
					}
				}

				u=v;
				v=v_next;
				assert(v!=-1);
				assert(!used[u][v]);
				used[u][v]=true;
				H.push_back(P[u]);
			}

			u=tmp;
		}

		if(is_ccw(H)) Q.push_back(H);
	}

	vector<int> den(Q.size()); // ガスの濃度
	rep(i,Q.size()) rep(j,n) if(cover(F[j],Q[i])) den[i]++;

	vector< vector<int> > d(Q.size(),vector<int>(Q.size(),INF));
	rep(i,Q.size()){
		d[i][i]=0;
		rep(j,Q[i].size()){
			int touch=-1;
			segment S(Q[i][j],Q[i][(j+1)%Q[i].size()]);
			rep(k,Q.size()) rep(l,Q[k].size()) {
				segment T(Q[k][l],Q[k][(l+1)%Q[k].size()]);
				if(S.a==T.b && S.b==T.a) touch=k;
			}
			if(touch!=-1){ // 辺と辺で接する
				d[i][touch]=abs(den[i]-den[touch]);
			}
			else{ // 辺と穴で接する
				int j=-1;
				rep(k,Q.size()) if(k!=i && cover(Q[k],Q[i]) && (j==-1 || cover(Q[j],Q[k]))) j=k;
				if(j!=-1){
					d[i][j]=d[j][i]=abs(den[i]-den[j]);
				}
			}
		}
	}
	rep(k,Q.size()) rep(i,Q.size()) rep(j,Q.size()) d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

	int q; scanf("%d",&q);
	while(q--){
		point s,t; scanf("%lf%lf%lf%lf",&s.x,&s.y,&t.x,&t.y);
		int i=-1,j=-1;
		rep(k,Q.size()){
			if(cover(Q[k],s) && (i==-1 || cover(Q[i],Q[k]))) i=k;
			if(cover(Q[k],t) && (j==-1 || cover(Q[j],Q[k]))) j=k;
		}
		printf("%d\n",d[i][j]);
	}

	return 0;
}

Measured memory_bytes: 1344