#include namespace { #pragma GCC diagnostic ignored "-Wunused-function" #include #pragma GCC diagnostic warning "-Wunused-function" using namespace std; using namespace atcoder; #define rep(i,n) for(int i = 0; i < (int)(n); i++) #define rrep(i,n) for(int i = (int)(n) - 1; i >= 0; i--) #define all(x) begin(x), end(x) #define rall(x) rbegin(x), rend(x) template bool chmax(T& a, const T& b) { if (a < b) { a = b; return true; } else return false; } template bool chmin(T& a, const T& b) { if (b < a) { a = b; return true; } else return false; } using ll = long long; using P = pair; using VI = vector; using VVI = vector; using VL = vector; using VVL = vector; const int di[] = {1, 0, -1, 0}; const int dj[] = {0, 1, 0, -1}; template struct Rerooting { const vector>& g; const int n; const int root; vector> dp, sl, sr; Rerooting(const vector>& g, int root=0): g(g), n(g.size()), root(root), dp(n), sl(n), sr(n) { dfs1(root); dfs2(root); } S dfs1(int u, int p=-1) { const int sz = g[u].size(); dp[u].resize(sz); sl[u].resize(sz + 1); sr[u].resize(sz + 1); S res; for(int i = 0; i < sz; i++) { const E& e = g[u][i]; int v = dest(e); if (v == p) continue; dp[u][i] = dfs1(v, u).apply(e); res = res.merge(dp[u][i]); } return res; } void dfs2(int u, int p=-1) { const int sz = g[u].size(); { S s; for(int i = 0; i < sz; i++) { s = s.merge(dp[u][i]); sl[u][i + 1] = s; } } { S s; for(int i = sz - 1; i >= 0; i--) { s = dp[u][i].merge(s); sr[u][i] = s; } } for(int i = 0; i < sz; i++) { int v = dest(g[u][i]); if (v == p) continue; const int sz_v = g[v].size(); for(int j = 0; j < sz_v; j++) { const E& e = g[v][j]; int w = dest(e); if (w != u) continue; dp[v][j] = sl[u][i].merge(sr[u][i + 1]).apply(e); break; } dfs2(v, u); } } S get_acc(int v) { return sr[v][0]; } S get_res(int v, E e) { return sr[v][0].apply(e); } private: int dest(const E& e) { if constexpr (is_same::value) return e; else return e.to; }; }; class mint61 { using ull = unsigned long long; using ui128 = __uint128_t; public: static constexpr unsigned long long mod = (1ULL << 61) - 1; ull v = 0; constexpr mint61() {} explicit constexpr mint61(ull x) { v = (x >> 61) + (x & mod); if (v >= mod) v -= mod; } static constexpr mint61 raw(ull x) { mint61 res; res.v = x; return res; } friend constexpr mint61 operator+(mint61 lhs, mint61 rhs) { auto res = lhs.v + rhs.v; return raw(res < mod ? res : res - mod); } friend constexpr mint61 operator-(mint61 lhs, mint61 rhs) { return raw(lhs.v >= rhs.v ? lhs.v - rhs.v : mod + lhs.v - rhs.v); } static constexpr ull multiply_loose_mod(mint61 lhs, mint61 rhs) { // ab = q(m+1)+r = qm+q+r // q+r = ab-qm = ab-floor(ab/(m+1))m < ab-(ab/(m+1)-1)m = ab/(m+1)+m <= // (m-1)^2/(m+1)+m = 2m-3+4/(m+1) auto mul = ui128(lhs.v) * rhs.v; return ull(mul >> 61) + ull(mul & mod); } friend constexpr mint61 operator*(mint61 lhs, mint61 rhs) { auto res = multiply_loose_mod(lhs, rhs); return raw(res < mod ? res : res - mod); } mint61& operator+=(mint61 rhs) { return *this = *this + rhs; } mint61& operator-=(mint61 rhs) { return *this = *this - rhs; } mint61& operator*=(mint61 rhs) { return *this = *this * rhs; } friend constexpr bool operator==(const mint61& lhs, const mint61& rhs) { return lhs.v == rhs.v; } friend ostream& operator<<(ostream& os, mint61 x) { return os << x.v; } }; std::mt19937 RNG(std::chrono::system_clock::now().time_since_epoch().count()); unsigned long long RULL(unsigned long long L, unsigned long long R) { assert(L < R); return std::uniform_int_distribution(L, R - 1)(RNG); } mint61 dh[100000]; // example: below is for ABC222-F struct S { int d = 0; mint61 h = mint61::raw(1ULL); S apply(int) const { return S{d + 1, dh[d] + h}; } S merge(const S& rhs) const { return S{max(d, rhs.d), h * rhs.h}; } bool operator==(const S&) const = default; }; void solve() { int n; cin >> n; vector> es(n - 1); int vcnt1 = n; for (auto& [u, v, w] : es) cin >> u >> v >> w, u--, v--, vcnt1 += w - 1; int h, w; cin >> h >> w; vector s(h); int vcnt2 = 0; rep(i, h) cin >> s[i], vcnt2 += count(all(s[i]), '#'); if (vcnt1 != vcnt2) { cout << "No\n"; return; } VVI g1(vcnt1), g2(vcnt2); int nxt = n; for (auto [u, v, w] : es) { int now = u; rep(_, w - 1) { g1[now].emplace_back(nxt); g1[nxt].emplace_back(now); now = nxt++; } g1[now].emplace_back(v); g1[v].emplace_back(now); } assert(nxt == vcnt1); nxt = 0; VVI id(h, VI(w, -1)); vector

id2idx(vcnt1); rep(i, h) rep(j, w) if (s[i][j] == '#') id[i][j] = nxt, id2idx[nxt] = {i, j}, nxt++; assert(nxt == vcnt2); rep(i, h) rep(j, w - 1) if (s[i][j] == '#' && s[i][j+1] == '#') { int u = id[i][j], v = id[i][j+1]; g2[u].emplace_back(v); g2[v].emplace_back(u); } rep(i, h - 1) rep(j, w) if (s[i][j] == '#' && s[i+1][j] == '#') { int u = id[i][j], v = id[i+1][j]; g2[u].emplace_back(v); g2[v].emplace_back(u); } Rerooting rt1(g1), rt2(g2); vector

ans(vcnt1); rep(r, vcnt1) if (rt1.get_acc(0) == rt2.get_acc(r)) { auto dfs = [&](auto&& self, int u1, int u2, int p1, int p2) -> void { ans[u1] = id2idx[u2]; pair cs1[3], cs2[3]; int sz1 = 0, sz2 = 0; rep(i, ssize(g1[u1])) { int c1 = g1[u1][i]; if (c1 != p1) cs1[sz1++] = {c1, rt1.dp[u1][i]}; } rep(i, ssize(g2[u2])) { int c2 = g2[u2][i]; if (c2 != p2) cs2[sz2++] = {c2, rt2.dp[u2][i]}; } assert(sz1 == sz2 && sz1 <= 3); ranges::sort(cs2, cs2 + sz2, {}, &pair::first); do { bool ok = true; rep(i, sz1) ok &= cs1[i].second == cs2[i].second; if (!ok) continue; rep(i, sz1) { self(self, cs1[i].first, cs2[i].first, u1, u2); } return; } while (ranges::next_permutation(cs2, cs2 + sz2, {}, &pair::first).found); assert(false); }; dfs(dfs, 0, r, -1, -1); cout << "Yes\n"; ans.resize(n); for (auto [x, y] : ans) cout << x + 1 << ' ' << y + 1 << '\n'; return; } cout << "No\n"; } } int main() { ios::sync_with_stdio(false); cin.tie(0); rep(i, ssize(dh)) dh[i] = mint61::raw(RULL(1, mint61::mod)); int tt; cin >> tt; while (tt--) { solve(); } }