#include<bits/stdc++.h>
using namespace std ;
#define F first
#define S second
#define g0 get<0>
#define g1 get<1>
#define g2 get<2>
const int N = 505 ;
const int W = 1e6+5 ;
int n , w , arr[N][N][2] , maxi[N][N] , mini[N][N] , par[N] ;
vector<tuple<int,int,int>> vt[2] , ans ;
int p(int k){
if(par[k]<0) return k ;
else return par[k]=p(par[k]) ;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) ;
cin >> n >> w ;
for(int l=1 ; l>=0 ; l--){
for(int i=1 ; i<n ; i++){
for(int j=0 ; j<i ; j++){
cin >> arr[i][j][l] ;
}
}
}
memset(mini,0x3f,sizeof(mini)) ;
for(int i=1 ; i<n ; i++){
for(int j=0 ; j<i ; j++){
if(w-arr[i][j][1]<=arr[i][j][0]) vt[0].push_back({-arr[i][j][0],i,j}) , vt[1].push_back({w-arr[i][j][1],i,j}) ;
}
}
// build minimum spanning tree in vt[0] and maximum spanning tree in vt[1]
for(int t=0 ; t<2 ; t++){
memset(par,-1,sizeof(par)) ;
sort(vt[t].begin(),vt[t].end()) ;
for(int i=0 ; i<vt[t].size() ; i++){
int u = g1(vt[t][i]) , v = g2(vt[t][i]) , pu = p(u) , pv = p(v) , wei = g0(vt[t][i]) ;
if(pu==pv) continue ;
if(par[pu]<=par[pv]) par[pu]+=par[pv] , par[pv]=pu ;
else par[pv]+=par[pu] , par[pu]=pv ;
if(!t) wei*=-1 ;
ans.push_back({u,v,wei}) ;
maxi[u][v]=maxi[v][u]=max(arr[u][v][0],w-arr[u][v][1]) ;
mini[u][v]=mini[v][u]=min(arr[u][v][0],w-arr[u][v][1]) ;
}
}
for(int l=0 ; l<n ; l++){
for(int i=0 ; i<n ; i++){
for(int j=0 ; j<n ; j++){
maxi[i][j]=max(maxi[i][j],min(maxi[i][l],maxi[l][j])) ;
mini[i][j]=min(mini[i][j],max(mini[i][l],mini[l][j])) ;
}
}
}
bool flag = ans.size()<=2023 ;
for(int i=1 ; i<n ; i++){
for(int j=0 ; j<i ; j++){
if(arr[i][j][0]!=maxi[i][j] || w-arr[i][j][1]!=mini[i][j]) flag = false ;
}
}
if(!flag){
cout << "NO\n" ;
return 0 ;
}
cout << ans.size() << '\n' ;
for(int i=0 ; i<ans.size() ; i++) cout << g0(ans[i]) << ' ' << g1(ans[i]) << ' ' << g2(ans[i]) << '\n' ;
return 0 ;
}