#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] <<    ;   }