#include <bits/stdc++.h>
using namespace std;
using ldb = long double;
struct Point { ldb x, y; };
struct Vec { ldb x, y; };
struct Line { ldb a, b, c; };
const ldb EPS = 1e-12;
const ldb FAR_COORD = 1e12L;
Vec vecto(const Point &A, const Point &B) { return {B.x - A.x, B.y - A.y}; }
ldb cross(const Vec &A, const Vec &B) { return A.x * B.y - A.y * B.x; }
bool onseg(const Point &A, const Point &B, const Point &P) {
return (min(A.x, B.x) - 1e-15 <= P.x && P.x <= max(A.x, B.x) + 1e-15 &&
min(A.y, B.y) - 1e-15 <= P.y && P.y <= max(A.y, B.y) + 1e-15);
}
Line make_line(const Point &A, const Point &B) {
Line r;
r.a = B.y - A.y;
r.b = A.x - B.x;
r.c = -r.a * A.x - r.b * A.y;
return r;
}
bool seg_intersect(const Point &A, const Point &B, const Point &C, const Point &D) {
Line L1 = make_line(A, B);
Line L2 = make_line(C, D);
ldb det = L1.a * L2.b - L2.a * L1.b;
if (fabsl(det) < EPS) {
// parallel; check colinear + overlap
if (fabsl(L1.a * C.x + L1.b * C.y + L1.c) < 1e-9) {
if (onseg(A, B, C) || onseg(A, B, D) || onseg(C, D, A) || onseg(C, D, B)) return true;
}
return false;
}
ldb x = (L2.c * L1.b - L1.c * L2.b) / det;
ldb y = (L1.c * L2.a - L2.c * L1.a) / det;
Point P = {x, y};
return onseg(A, B, P) && onseg(C, D, P);
}
bool point_in_polygon(const Point &pt, const vector<Point> &poly) {
int n = (int)poly.size();
// ray to a far point
Point farp = { FAR_COORD, FAR_COORD + 12345.0L };
int cnt = 0;
bool onboundary = false;
for (int i = 0; i < n; ++i) {
int j = (i + 1) % n;
Point A = poly[i], B = poly[j];
// check if point is on edge
ldb cr = cross(vecto(A, B), vecto(A, pt));
if (fabsl(cr) < 1e-12 && onseg(A, B, pt)) { onboundary = true; break; }
if (seg_intersect(A, B, pt, farp)) ++cnt;
}
if (onboundary) return true;
return (cnt % 2 == 1);
}
ldb euclid_dist(const Point &A, const Point &B) {
ldb dx = A.x - B.x, dy = A.y - B.y;
return sqrt((double)(dx*dx + dy*dy));
}
ldb trans_prob(const Point &A, const Point &B) {
ldb D = euclid_dist(A, B);
if (D > 1000.0L) D = 1000.0L;
return 1.0L - D / 1000.0L;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
if (!(cin >> T)) return 0;
while (T--) {
int N, M;
cin >> N >> M;
vector<vector<Point>> layer(N);
for (int i = 0; i < N; ++i) {
int A; cin >> A;
layer[i].resize(A);
for (int j = 0; j < A; ++j) cin >> layer[i][j].x >> layer[i][j].y;
}
vector<Point> players(M);
for (int i = 0; i < M; ++i) cin >> players[i].x >> players[i].y;
// vec[k] = list of player indices in layer k (0 = innermost)
vector<vector<int>> vec(N);
vector<int> which_layer(M, -1);
for (int i = 0; i < M; ++i) {
int pos = -1;
// find smallest k such that player is inside layer[k]; because layers nested from 0..N-1 (inner->outer)
for (int k = 0; k < N; ++k) {
if (point_in_polygon(players[i], layer[k])) {
pos = k;
break;
}
}
if (pos == -1) {
// If not inside any polygon, it must be outside all (i.e., beyond outermost)
pos = N; // outside all; but per statement every player is not on walls, and there is at least one outside outermost
}
which_layer[i] = pos;
if (pos >= 0 && pos < N) vec[pos].push_back(i);
// If pos==N (outside all), we can treat them as layer N (outside). But in the problem players outside outermost are considered "outside".
// To simplify, we'll put those with pos==N into a separate vector index N-1? Actually problem states there is at least one player outside outermost:
// We'll handle transmissions from layer N-1 to outside group: so we need container for outside players:
}
// Build list for outside (outside of layer N-1). Let's collect indices with which_layer == N separately.
vector<int> outside_players;
for (int i = 0; i < M; ++i) if (which_layer[i] == N) outside_players.push_back(i);
// We will allow transmissions:
// from vec[k] -> vec[k+1] for k = 0..N-2
// from vec[N-1] -> outside_players
// find the unique player in innermost (layer 0) (problem guarantees exactly one)
int start = -1;
if (!vec[0].empty()) {
// problem guarantees exactly one player inside the innermost
start = vec[0][0];
} else {
// defensive: if none found, pick any with which_layer==0 (shouldn't happen)
for (int i = 0; i < M; ++i) if (which_layer[i] == 0) { start = i; break; }
}
// multiplicative Dijkstra (maximize product of probabilities)
vector<ldb> prob(M, -1.0L);
if (start == -1) {
// no start found - but per statement shouldn't happen
cout << 0 << '\n';
continue;
}
prob[start] = 1.0L;
priority_queue<pair<ldb,int>> pq; // max-heap by first
pq.push({prob[start], start});
auto relax_edge = [&](int u, int v) {
ldb w = trans_prob(players[u], players[v]);
ldb cand = prob[u] * w;
if (cand > prob[v] + 1e-15L) {
prob[v] = cand;
pq.push({prob[v], v});
}
};
while (!pq.empty()) {
auto cur = pq.top(); pq.pop();
ldb curp = cur.first;
int u = cur.second;
if (curp + 1e-15L < prob[u]) continue; // stale
int layer_u = which_layer[u];
if (layer_u >= 0 && layer_u <= N-2) {
// edges to next layer's players
for (int v : vec[layer_u + 1]) relax_edge(u, v);
} else if (layer_u == N-1) {
// edges to outside players
for (int v : outside_players) relax_edge(u, v);
}
// if point is already outside (which_layer == N), no further edges
}
// answer = max prob among players that are outside the outermost
ldb best = 0.0L;
if (!outside_players.empty()) {
for (int v : outside_players) best = max(best, prob[v]);
} else {
// maybe the "outside" players were placed into vec[N-1]? but per above we separated.
// Another possibility: players in layer N-1 are considered "outside outermost"? No.
// If no explicit outside players, maybe some players lie exactly outside but we didn't detect => fallback: consider any player in layer N-1 with no further layer as "outside"
for (int i = 0; i < M; ++i) if (which_layer[i] == N-1) best = max(best, prob[i]);
}
// output floor(best * 1000)
long long outv = (long long) floor((double)(best * 1000.0L + 1e-12));
cout << outv << '\n';
}
return 0;
}