#include <bits/stdc++.h>
using namespace std;
const long long mod = 1000000007;
long long powmod(long long a, long long b) {
  long long res = 1;
  a %= mod;
  for (; b; b >>= 1) {
    if (b & 1) res = res * a % mod;
    a = a * a % mod;
  }
  return res;
}
int n, m, l, a;
int idx[400005][2];
vector<int> model;
vector<vector<int> > clauses;
vector<bool> satisfied;
bool impossible;
int cntDetermined;
stack<pair<vector<int>, vector<int> > > st;
bool isDeterministic(int i) {
  int k = idx[i][0];
  if (i > m) i -= m;
  for (int l = 0; l < (int)clauses[k].size(); l++) {
    int ii = clauses[k][l];
    if (abs(ii) == i) continue;
    if (model[abs(ii)] == -1) return 0;
  }
  return 1;
}
void findModel(int i);
void updateSatisfied(int i) {
  satisfied[i] = 1;
  for (int j = 0; j < (int)clauses[i].size(); j++) {
    int next = clauses[i][j];
    if (model[abs(next)] == -1) {
      if (next < 0) next = abs(next) + m;
      if (idx[next][0] == i)
        idx[next][0] = idx[next][1];
      else
        idx[next][1] = -1;
      if (idx[next][0] == -1) {
        if (next > m) next -= m;
        findModel(next);
      }
    }
  }
}
void findModel(int i) {
  if (idx[i][0] == -1 && idx[i + m][0] == -1) {
    model[i] = 1;
    cntDetermined++;
    return;
  } else if (idx[i][0] == -1) {
    model[i] = 0;
    cntDetermined++;
    if (satisfied[idx[i + m][0]] == 0) updateSatisfied(idx[i + m][0]);
    if (idx[i + m][1] != -1 && satisfied[idx[i + m][1]] == 0)
      updateSatisfied(idx[i + m][1]);
  } else if (idx[i + m][0] == -1) {
    model[i] = 1;
    cntDetermined++;
    if (satisfied[idx[i][0]] == 0) updateSatisfied(idx[i][0]);
    if (idx[i][1] != -1 && satisfied[idx[i][1]] == 0)
      updateSatisfied(idx[i][1]);
  } else {
    if (satisfied[idx[i][0]] && satisfied[idx[i + m][0]]) {
      model[i] = 1;
      cntDetermined++;
      return;
    } else if (satisfied[idx[i][0]]) {
      model[i] = 0;
      cntDetermined++;
      updateSatisfied(idx[i + m][0]);
      return;
    } else if (satisfied[idx[i + m][0]]) {
      model[i] = 1;
      cntDetermined++;
      updateSatisfied(idx[i][0]);
      return;
    }
    bool determined = isDeterministic(i);
    if (determined) {
      model[i] = 1;
      cntDetermined++;
      if (satisfied[idx[i][0]] == 0) updateSatisfied(idx[i][0]);
      return;
    }
    determined = isDeterministic(i + m);
    if (determined) {
      model[i] = 0;
      cntDetermined++;
      if (satisfied[idx[i + m][0]] == 0) updateSatisfied(idx[i + m][0]);
      return;
    }
  }
}
void findModel(int i, vector<int>& idx1, vector<int>& idx2);
void updateSatisfied(int i, vector<int>& idx1, vector<int>& idx2) {
  satisfied[i] = 1;
  idx2.push_back(i);
  for (int j = 0; j < (int)clauses[i].size(); j++) {
    int next = clauses[i][j];
    if (model[abs(next)] == -1) {
      if (next < 0) next = abs(next) + m;
      if (idx[next][0] == i)
        idx[next][0] = idx[next][1];
      else
        idx[next][1] = -1;
      if (idx[next][0] == -1) {
        if (next > m) next -= m;
        findModel(next, idx1, idx2);
      }
    }
  }
}
void findModel(int i, vector<int>& idx1, vector<int>& idx2) {
  if (idx[i][0] == -1 && idx[i + m][0] == -1) {
    model[i] = 1;
    idx1.push_back(i);
    cntDetermined++;
    return;
  } else if (idx[i][0] == -1) {
    model[i] = 0;
    idx1.push_back(i);
    cntDetermined++;
    if (satisfied[idx[i + m][0]] == 0) updateSatisfied(idx[i + m][0]);
    if (idx[i + m][1] != -1 && satisfied[idx[i + m][1]] == 0)
      updateSatisfied(idx[i + m][1]);
  } else if (idx[i + m][0] == -1) {
    model[i] = 1;
    idx1.push_back(i);
    cntDetermined++;
    if (satisfied[idx[i][0]] == 0) updateSatisfied(idx[i][0]);
    if (idx[i][1] != -1 && satisfied[idx[i][1]] == 0)
      updateSatisfied(idx[i][1]);
  } else {
    if (satisfied[idx[i][0]] && satisfied[idx[i + m][0]]) {
      model[i] = 1;
      idx1.push_back(i);
      cntDetermined++;
      return;
    } else if (satisfied[idx[i][0]]) {
      model[i] = 0;
      idx1.push_back(i);
      cntDetermined++;
      updateSatisfied(idx[i + m][0]);
      return;
    } else if (satisfied[idx[i + m][0]]) {
      model[i] = 1;
      idx1.push_back(i);
      cntDetermined++;
      updateSatisfied(idx[i][0]);
      return;
    }
    bool determined = isDeterministic(i);
    if (determined) {
      model[i] = 1;
      idx1.push_back(i);
      cntDetermined++;
      if (satisfied[idx[i][0]] == 0) updateSatisfied(idx[i][0]);
      return;
    }
    determined = isDeterministic(i + m);
    if (determined) {
      model[i] = 0;
      idx1.push_back(i);
      cntDetermined++;
      if (satisfied[idx[i + m][0]] == 0) updateSatisfied(idx[i + m][0]);
      return;
    }
  }
}
bool isCorrectModel() {
  for (int i = 0; i < (int)n; i++) {
    bool possible = false;
    for (int j = 0; j < (int)clauses[i].size(); j++) {
      int ii = clauses[i][j];
      if (ii > 0 && model[ii] == 1) {
        possible = true;
        break;
      } else if (ii < 0 && model[-ii] == 0) {
        possible = true;
        break;
      }
    }
    if (!possible) return false;
  }
  return true;
}
bool fullSearch(int lim) {
  if (cntDetermined == m) {
    if (isCorrectModel()) {
      return true;
    }
    return false;
  }
  for (int j = lim; j < (int)m + 1; j++) {
    if (model[j] == -1) {
      for (int k = 0; k < (int)2; k++) {
        vector<int> idx1, idx2;
        model[j] = k;
        cntDetermined++;
        if (satisfied[idx[j + m * (1 - k)][0]] == 0) {
          satisfied[idx[j + m * (1 - k)][0]] = 1;
          idx2.push_back(idx[j + m * (1 - k)][0]);
        }
        idx1.push_back(j);
        while (1) {
          int cnt = cntDetermined;
          bool next = false;
          for (int i = 1; i < (int)m + 1; i++) {
            if (model[i] == -1) {
              next = true;
              findModel(i, idx1, idx2);
            }
          }
          if (cnt == cntDetermined) break;
          if (!next || impossible) break;
        }
        st.push(make_pair(idx1, idx2));
        if (fullSearch(j + 1))
          return true;
        else {
          vector<int> idx1 = st.top().first, idx2 = st.top().second;
          st.pop();
          cntDetermined -= idx1.size();
          for (int l = 0; l < (int)idx1.size(); l++) model[idx1[l]] = -1;
          for (int l = 0; l < (int)idx2.size(); l++) satisfied[idx2[l]] = 0;
          continue;
        }
      }
      return false;
    }
  }
}
int main() {
  cin >> n >> m;
  model.resize(m + 1, -1);
  memset(idx, -1, sizeof(idx));
  for (int i = 0; i < (int)n; i++) {
    cin >> l;
    vector<int> clause(l);
    for (int j = 0; j < (int)l; j++) {
      cin >> a;
      clause[j] = a;
      if (a < 0) a = abs(a) + m;
      if (idx[a][0] == -1)
        idx[a][0] = i;
      else
        idx[a][1] = i;
    }
    clauses.push_back(clause);
  }
  satisfied.resize(n, 0);
  impossible = false;
  cntDetermined = 0;
  int lim = 1;
  while (1) {
    int cnt = cntDetermined;
    bool next = false;
    int lim1 = -1;
    for (int i = lim; i < (int)m + 1; i++) {
      if (model[i] == -1) {
        if (lim1 == -1) lim1 = i;
        next = true;
        findModel(i);
      }
    }
    lim = lim1;
    if (cnt == cntDetermined) break;
    if (!next || impossible) break;
  }
  if (cntDetermined != m) {
    fullSearch(1);
  }
  impossible = !isCorrectModel();
  if (impossible)
    cout << "NO" << endl;
  else {
    cout << "YES" << endl;
    for (int i = 1; i < (int)m + 1; i++) cout << model[i];
    cout << endl;
  }
  return 0;
}
