#include <bits/stdc++.h>
using namespace std;
long long MOD = 1000000007;
struct edge {
  int from, to, x1, x2;
  bool operator<(const edge& e) const {
    if (e.from == from) return to < e.to;
    return from < e.from;
  }
  bool operator==(const edge& e) const {
    return from == e.from && to == e.to && x1 == e.x1 && x2 == e.x2;
  }
};
vector<edge> List[200100];
inline bool what(edge e, bool f) {
  if (f == 0) {
    if (e.x1 > 0)
      return 1;
    else
      return 0;
  } else
    return e.x2 > 0;
}
void dfs(int v, vector<bool>& vis, vector<int>& val) {
  for (edge e : List[v]) {
    int c = e.to;
    if (vis[c]) continue;
    vis[c] = true;
    val[abs(e.x1)] = what(e, 1);
    dfs(c, vis, val);
  }
}
bool get_cycle(int v, vector<edge>& cycle, vector<bool>& vis,
               vector<edge>& par) {
  vis[v] = true;
  for (edge e : List[v]) {
    int c = e.to;
    if ((edge){e.to, e.from, e.x2, e.x1} == par[v]) continue;
    if (vis[c]) {
      cycle.push_back(e);
      int cur = v;
      while (cur != c) {
        cycle.push_back(par[cur]);
        cur = par[cur].from;
      }
      return 1;
    } else {
      par[c] = e;
      if (get_cycle(c, cycle, vis, par)) return 1;
    }
  }
  return 0;
}
int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  vector<bool> vis_nd(n + 1, 0);
  vector<vector<std::pair<int, int> > > tmp_list(m + 1);
  vector<int> val_cnf(m + 1, -1);
  vector<vector<int> > inp(n + 1);
  for (int i = 1; i <= n; ++i) {
    int k;
    scanf("%d", &k);
    while (k--) {
      int x;
      scanf("%d", &x);
      tmp_list[abs(x)].push_back(make_pair(i, x));
      inp[i].push_back(x);
    }
  }
  vector<edge> same_valued_edges;
  for (int i = 1; i <= m; ++i) {
    if (tmp_list[i].empty())
      continue;
    else if (tmp_list[i].size() == 1) {
      std::pair<int, int> p = tmp_list[i].back();
      List[p.first].push_back((edge){p.first, p.first, p.second, p.second});
    } else if (tmp_list[i].size() == 2) {
      std::pair<int, int> p1 = tmp_list[i][0];
      std::pair<int, int> p2 = tmp_list[i][1];
      if (p1.first == p2.first) {
        List[p1.first].push_back(
            (edge){p1.first, p1.first, p1.second, p1.second});
      } else {
        List[p1.first].push_back(
            (edge){p1.first, p2.first, p1.second, p2.second});
        List[p2.first].push_back(
            (edge){p2.first, p1.first, p2.second, p1.second});
        if (p1.second == p2.second)
          same_valued_edges.push_back(
              (edge){p1.first, p2.first, p1.second, p2.second});
      }
    } else
      assert(0);
  }
  for (edge e : same_valued_edges) {
    int u = e.from;
    int v = e.to;
    if (vis_nd[u]) {
      assert(vis_nd[v]);
      continue;
    }
    val_cnf[abs(e.x1)] = what(e, 0);
    vis_nd[u] = true;
    dfs(u, vis_nd, val_cnf);
    assert(vis_nd[v]);
  }
  vector<bool> vis(n + 1, 0);
  vector<edge> par(n + 1, (edge){-1, -1, -1, -1});
  for (int i = 1; i <= n; ++i) {
    if (vis_nd[i]) continue;
    vector<edge> cycle;
    get_cycle(i, cycle, vis, par);
    if (cycle.empty()) {
      puts("NO");
      return 0;
    }
    for (edge e : cycle) {
      vis_nd[e.from] = true;
      val_cnf[abs(e.x1)] = what(e, 0);
    }
    for (edge e : cycle) {
      dfs(e.from, vis_nd, val_cnf);
    }
  }
  for (int i = 1; i <= m; ++i) {
    if (val_cnf[i] == -1) val_cnf[i] = 1;
  }
  bool flag = 1;
  for (int i = 1; i <= n; ++i) {
    bool f = 0;
    for (int x : inp[i]) {
      if (x > 0)
        f |= val_cnf[x];
      else
        f |= (!val_cnf[-x]);
    }
    flag &= f;
  }
  if (!flag)
    puts("NO");
  else {
    puts("YES");
    for (int i = 1; i <= m; ++i) printf("%d", val_cnf[i]);
    putchar(10);
  }
  return 0;
}
