#include using namespace std; const int INF = 1e7; // DSU int root(int i, vector &parent) { return parent[i] < 0 ? i : (parent[i] = root(parent[i], parent)); } void unite(int i, int j, vector &parent) { i = root(i, parent), j = root(j, parent); if (i == j) return; if (parent[i] > parent[j]) swap(i, j); parent[i] += parent[j]; parent[j] = i; } vector> solve() { int n, W; cin >> n >> W; vector> B(n, vector(n)), C(n, vector(n)); for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) cin >> C[i][j], C[j][i] = C[i][j]; } int mnB = INF, mxB = 0; for (int i = 1; i < n; ++i) { for (int j = 0; j < i; ++j) { cin >> B[i][j], B[j][i] = B[i][j]; mnB = min(mnB, B[i][j]); mxB = max(mxB, B[i][j]); } } vector> streets; if (mnB == mxB) { for (int i = 0; i < n-1; ++i) streets.emplace_back(i, i+1, mnB); int smallC = W-mnB; // cannot build C lower than this // sort C by weight vector> edges; for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { if (C[i][j] < smallC) return {}; edges.emplace_back(C[i][j], i, j); } } sort(edges.begin(), edges.end()); vector parent(n, -1); while (!edges.empty()) { int curC = get<0>(edges.back()); for (int i = (int)edges.size()-1; i >= 0 && get<0>(edges[i]) == curC; --i) { int a = get<1>(edges[i]), b = get<2>(edges[i]); if (root(a, parent) == root(b, parent)) return {}; // reachable with larger edges } for (int i = (int)edges.size()-1; i >= 0 && get<0>(edges[i]) == curC; --i) { int a = get<1>(edges[i]), b = get<2>(edges[i]); if (root(a, parent) != root(b, parent)) unite(a, b, parent), streets.emplace_back(a, b, W-curC); edges.pop_back(); } } return streets; } else if (W == 1) { vector parentB(n, -1), parentC(n, -1), parent(n, -1); for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { if (B[i][j] == 1) unite(i, j, parentB), unite(i, j, parent); if (C[i][j] == 1) unite(i, j, parentC), unite(i, j, parent); } } if (parent[root(0, parent)] != -n) return {}; // all connected for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { if (B[i][j] == 0 && root(i, parentB) == root(j, parentB)) return {}; if (C[i][j] == 0 && root(i, parentC) == root(j, parentC)) return {}; } } for (int i = 0; i < n; ++i) { if (parentB[i] >= 0) streets.emplace_back(i, root(i, parentB), 1); if (parentC[i] >= 0) streets.emplace_back(i, root(i, parentC), 0); } return streets; } else { vector> dB(n, vector(n, -1)), dC(n, vector(n, -1)); for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { if (B[i][j] + C[i][j] >= W) { streets.emplace_back(i, j, B[i][j]); dB[j][i] = dB[i][j] = max(dB[i][j], B[i][j]); streets.emplace_back(i, j, W-C[i][j]); dC[j][i] = dC[i][j] = max(dC[i][j], C[i][j]); } } } // Floyd for (int k = 0; k < n; ++k) { for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { dB[i][j] = max(dB[i][j], min(dB[i][k], dB[k][j])); dC[i][j] = max(dC[i][j], min(dC[i][k], dC[k][j])); } } } for (int i = 0; i < n; ++i) { for (int j = i+1; j < n; ++j) { if (dB[i][j] != B[i][j] || dC[i][j] != C[i][j]) return {}; } } return streets; } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0); vector> streets = solve(); if (streets.empty()) { cout << "NO" << endl; } else { cout << streets.size() << '\n'; for (auto [u, v, b] : streets) cout << u << ' ' << v << ' ' << b << '\n'; } return 0; }