/*2-sat启蒙题目*/
/*其实2-sat我个人理解就是根据题目写出最终答案必然出现的情况的关系(可能多个) 然后判断能不能构成连通图*/
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <set>
#include <vector>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 3e5;
int n, m, tot;
int door[maxn];
int mark[maxn];
vector<int>G[maxn];
vector<int>v[maxn];
int c = 0;
int s[maxn];
void addedge(int x, int xval, int y, int yval) {
x = x * 2 + xval;
y = y * 2 + yval;
G[x ^ 1].push_back(y);
G[y ^ 1].push_back(x);
}
bool dfs(int x) {
if (mark[x ^ 1]) return false;
if (mark[x]) return true;
mark[x] = true;
s[c++] = x;
int len = G[x].size();
for (int i = 0; i < len; ++i) {
if (!dfs(G[x][i]))
return false;
}
return true;
}
bool solve() {
for (int i = 0; i < m * 2; i += 2) {
if (!mark[i] && !mark[i + 1]) {
c = 0;
if (!dfs(i)) {
while (c > 0) mark[s[--c]] = false;
if (!dfs(i + 1)) return false;
}
}
}
return true;
}
void test() {
ios::sync_with_stdio(false);
cin >> n >> m;
for (int i = 0; i < n; ++i) cin >> door[i];
for (int i = 0; i < m; ++i) {
int x; cin >> x;
for (int j = 0; j < x; ++j) {
int y; cin >> y;
v[y - 1].push_back(i);
}
}
for (int i = 0; i < m * 2; ++i)
G[i].clear();
memset(mark, 0, sizeof mark);
for (int i = 0; i < n; ++i) {
if (door[i]) {
addedge(v[i][0], 0, v[i][1], 1);
addedge(v[i][0], 1, v[i][1], 0);
}
else {
addedge(v[i][0], 0, v[i][1], 0);
addedge(v[i][0], 1, v[i][1], 1);
}
}
cout << (solve() ? "YES" : "NO") << endl;
}
int main() {
test();
return 0;
}