#include <bits/stdc++.h>
template <class T = double>
struct Point {
  T x, y;
  Point() : x(T()), y(T()) {}
  Point(T x, T y) : x(x), y(y) {}
  bool operator<(const Point p) const {
    if (x != p.x) return x < p.x;
    return y < p.y;
  }
  bool operator==(const Point p) const { return x == p.x && y == p.y; }
  Point operator+(const Point p) const { return Point(x + p.x, y + p.y); }
  Point operator-(const Point p) const { return Point(x - p.x, y - p.y); }
  Point operator*(T v) const { return Point(x * v, y * v); }
  Point operator/(T v) const { return Point(x / v, y / v); }
  template <class T2>
  operator Point<T2>() const {
    return Point<T2>(x, y);
  }
  T dot(Point p) const { return x * p.x + y * p.y; }
  T cross(Point p) const { return x * p.y - y * p.x; }
  double dist() const { return sqrt(static_cast<double>(dist2())); }
  T dist2() const { return x * x + y * y; }
  double angle() const { return atan2(y, x); }
  Point unit() const { return *this / dist(); }
  Point perp() const { return Point(-y, x); }
  Point rotate(double radians) {
    return Point(x * cos(radians) - y * sin(radians),
                 x * sin(radians) + y * cos(radians));
  }
};
template <class T = int>
struct BinaryIndexedTree {
  int size;
  int logSize;
  std::vector<T> tree;
  BinaryIndexedTree(int size)
      : size(size),
        logSize(sizeof(T) * 8 - __builtin_clz(size) - 1),
        tree(size + 1) {}
  void add(int index, T value) {
    assert(index >= 1 && index <= size);
    while (index <= size) {
      tree[index] += value;
      index += index & (-index);
    }
  }
  T getSum(int index) {
    assert(index <= size);
    T sum = T();
    while (index > 0) {
      sum += tree[index];
      index -= index & (-index);
    }
    return sum;
  }
  T getSum(int l, int r) { return getSum(r) - getSum(l - 1); }
  int lowerBound(T value) {
    T sum = T();
    int pos = 0;
    for (int i = logSize; i >= 0; i--) {
      if (pos + (1 << i) < size && sum + tree[pos + (1 << i)] < value) {
        sum += tree[pos + (1 << i)];
        pos += (1 << i);
      }
    }
    return pos + 1;
  }
};
template <class T = int>
T gcd(T a, T b) {
  if (b == 0) {
    return (a < 0 ? -a : a);
  }
  return gcd(b, a % b);
}
struct Node {
  std::vector<double> angles;
};
struct Query {
  int l, r;
  int ans;
};
const int MAXN = 100005;
BinaryIndexedTree<int> *bit;
std::map<Point<long long>, int> map;
int totAngles = 0;
std::vector<int> angles[MAXN];
int last[300005] = {};
Query qu[MAXN];
std::vector<Query *> quByR[MAXN];
int main() {
  int n;
  scanf("%d", &n);
  bit = new BinaryIndexedTree<int>(n);
  for (int i = 0; i < n; i++) {
    int k;
    scanf("%d", &k);
    std::vector<Point<long long>> points;
    for (int i2 = 0; i2 < k; i2++) {
      Point<int> p;
      scanf("%d %d", &p.x, &p.y);
      points.push_back(p);
    }
    for (int i2 = 0; i2 < points.size(); i2++) {
      Point<long long> p = points[(i2 + 1) % points.size()] - points[i2];
      int g = gcd(p.x, p.y);
      p.x /= g;
      p.y /= g;
      if (!map[p]) map[p] = ++totAngles;
      angles[i].push_back(map[p]);
    }
  }
  int q;
  scanf("%d", &q);
  for (int i = 0; i < q; i++) {
    scanf("%d %d", &qu[i].l, &qu[i].r);
    quByR[qu[i].r].push_back(&qu[i]);
  }
  for (int i = 1; i <= n; i++) {
    for (int i2 = 0; i2 < angles[i - 1].size(); i2++) {
      int lastIx = last[angles[i - 1][i2]];
      if (lastIx) {
        bit->add(lastIx, -1);
      }
      bit->add(i, 1);
      last[angles[i - 1][i2]] = i;
    }
    for (int i2 = 0; i2 < quByR[i].size(); i2++) {
      Query &q = *quByR[i][i2];
      q.ans = bit->getSum(q.l, q.r);
    }
  }
  for (int i = 0; i < q; i++) {
    printf("%d\n", qu[i].ans);
  }
  return 0;
}
