#include <bits/stdc++.h>
inline int readChar();
template <class T = int>
inline T readInt();
template <class T>
inline void writeInt(T x, char end = 0);
inline void writeChar(int x);
inline void writeWord(const char* s);
static const int buf_size = 4096;
inline int getChar() {
  static char buf[buf_size];
  static int len = 0, pos = 0;
  if (pos == len) pos = 0, len = fread(buf, 1, buf_size, stdin);
  if (pos == len) return -1;
  return buf[pos++];
}
inline int readChar() {
  int c = getChar();
  while (c <= 32) c = getChar();
  return c;
}
template <class T>
inline T readInt() {
  int s = 1, c = readChar();
  T x = 0;
  if (c == '-') s = -1, c = getChar();
  while ('0' <= c && c <= '9') x = x * 10 + c - '0', c = getChar();
  return s == 1 ? x : -x;
}
static int write_pos = 0;
static char write_buf[buf_size];
inline void writeChar(int x) {
  if (write_pos == buf_size)
    fwrite(write_buf, 1, buf_size, stdout), write_pos = 0;
  write_buf[write_pos++] = x;
}
template <class T>
inline void writeInt(T x, char end) {
  if (x < 0) writeChar('-'), x = -x;
  char s[24];
  int n = 0;
  while (x || !n) s[n++] = '0' + x % 10, x /= 10;
  while (n--) writeChar(s[n]);
  if (end) writeChar(end);
}
inline void writeWord(const char* s) {
  while (*s) writeChar(*s++);
}
struct Flusher {
  ~Flusher() {
    if (write_pos) fwrite(write_buf, 1, write_pos, stdout), write_pos = 0;
  }
} flusher;
using namespace std;
struct static_graph {
  int colors[500000];
  int firstv[500000];
  set<int> pool;
  static const int N = 500000;
  static const int M = 900000;
  struct edge {
    int v;
    edge* next;
  } edges[M];
  int nedges;
  struct node {
    vector<int>* ice;
    int prev_colors;
    bool depth_use;
    edge* firstedge;
    inline void init() { firstedge = NULL; };
    inline edge* add_edge(edge* e) {
      e->next = firstedge;
      firstedge = e;
      return firstedge;
    };
  } nodes[N];
  int nnodes;
  static_graph() { nnodes = 0, nedges = 0; };
  inline node& new_node() {
    node& r = nodes[nnodes++];
    return r;
  }
  inline edge* new_edge() { return &(edges[nedges++]); };
  inline edge* add_edge(int a, int b) {
    edge* e = new_edge();
    e->v = b;
    return nodes[a].add_edge(e);
  };
  inline void add_bi_edge(int a, int b) {
    add_edge(a, b);
    add_edge(b, a);
  };
  void depth_go(int index, int prev) {
    node& cur = nodes[index];
    if (cur.depth_use++) return;
    for (int x : (*cur.ice))
      if (colors[x]) pool.erase(colors[x]);
    for (int x : (*cur.ice))
      if (!colors[x]) {
        colors[x] = (*pool.upper_bound(0));
        firstv[x] = index;
        pool.erase(colors[x]);
      }
    for (int x : (*cur.ice)) pool.insert(colors[x]);
    for (edge* e = cur.firstedge; e; e = e->next) {
      depth_go(e->v, index);
    };
  };
  void depth_run(int first) {
    chrono::time_point<chrono::high_resolution_clock> start, end;
    start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < nnodes; i++) {
      node& cur = nodes[i];
      cur.depth_use = false;
    };
    depth_go(first, -1);
  };
  vector<node*> depth_to_wide(int first) {}
  void read_graph(istream* f){};
};
static_graph g;
int main() {
  istream& f = cin;
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  chrono::time_point<chrono::high_resolution_clock> start, end;
  start = std::chrono::high_resolution_clock::now();
  int n, m, c, x = 0;
  n = readInt<int>();
  m = readInt<int>();
  for (int i = 0; i < n; i++) {
    c = readInt<int>();
    static_graph::node& cur = g.new_node();
    cur.ice = new vector<int>();
    cur.ice->resize(c);
    cur.prev_colors = 0;
    for (int t = 0; t < c; t++) {
      x = readInt<int>();
      (*cur.ice)[t] = x - 1;
    };
    sort((*cur.ice).begin(), (*cur.ice).end());
    ;
  };
  for (int i = 0; i < n - 1; i++) {
    int a, b;
    a = readInt<int>(), b = readInt<int>();
    g.add_bi_edge(a - 1, b - 1);
  };
  for (int i = 0; i < m; i++) g.colors[i] = 0;
  for (int i = 0; i < m; i++) g.pool.insert(i + 1);
  g.depth_run(0);
  int mx = 1;
  for (int i = 0; i < m; i++) {
    mx = max(mx, g.colors[i]);
    if (!g.colors[i]) g.colors[i] = 1;
  }
  cout << mx << endl;
  for (int i = 0; i < m; i++) cout << g.colors[i] << " ";
}
