#include <iostream>
#include <vector>
#include <string>
#include <numeric>
// --- Khai báo biến toàn cục ---
const int MAXN = 300005; // Kích thước tối đa cho các mảng
int n, k; // n: số bóng đèn, k: số tập hợp
std::string s; // Chuỗi trạng thái ban đầu của các bóng đèn
std::vector<int> bulb_to_sets[MAXN]; // Mảng vector, lưu các tập hợp mà mỗi bóng đèn thuộc về
// --- Các cấu trúc dữ liệu cho Disjoint Set Union (DSU) ---
int parent[MAXN]; // Mảng cha, parent[i] là nút cha của nút i
int val[MAXN]; // val[i] lưu kết quả của (giá trị nút i) XOR (giá trị nút cha của nó)
// Đây là trọng số trên cạnh từ i đến parent[i]
int sz[MAXN][2]; // Với mỗi gốc của một thành phần liên thông, lưu kích thước của nó.
// sz[root][0]: số nút có giá trị CÙNG với gốc
// sz[root][1]: số nút có giá trị KHÁC với gốc
int total_min_ops = 0; // Tổng số thao tác tối thiểu cần thiết
// --- Hàm tìm gốc của một tập hợp (Find operation) ---
// Sử dụng kỹ thuật nén đường đi (path compression) và cập nhật trọng số XOR
int find_set(int v) {
if (v == parent[v]) {
// Nếu v là gốc, trả về chính nó
return v;
}
// Đệ quy để tìm gốc cuối cùng của chuỗi cha
int root = find_set(parent[v]);
// Trong quá trình nén đường đi, cập nhật val[v]
// val[v] mới = val[v] cũ ^ val[parent[v]] cũ
val[v] ^= val[parent[v]];
// Nén đường đi: nối v trực tiếp với gốc
parent[v] = root;
return root;
}
// --- Hàm tính chi phí cho một thành phần liên thông ---
int get_cost(int v) {
// Nếu thành phần này đã được nối với nút cơ sở (k+1), giá trị của nó là cố định.
// Chi phí lúc này chính là số nút phải bật (có giá trị 1).
// Vì nút gốc (của k+1) có giá trị 0, nên chi phí là số nút có giá trị khác gốc.
if (find_set(v) == find_set(k + 1)) {
return sz[v][1];
}
// Nếu thành phần là tự do, ta có thể chọn giá trị cho gốc là 0 hoặc 1.
// Ta chọn phương án tốn ít thao tác hơn.
return std::min(sz[v][0], sz[v][1]);
}
// --- Hàm hợp nhất hai tập hợp (Unite operation) ---
void unite_sets(int u, int v, int w) {
int root_u = find_set(u);
int root_v = find_set(v);
// w là ràng buộc yêu cầu: giá trị(u) ^ giá trị(v) = w
// Sau khi chạy find_set, ta có:
// giá trị(u) = giá trị(root_u) ^ val[u]
// giá trị(v) = giá trị(root_v) ^ val[v]
// Thay vào ràng buộc, ta có: giá trị(root_u) ^ giá trị(root_v) = w ^ val[u] ^ val[v]
int required_xor = w ^ val[u] ^ val[v];
if (root_u != root_v) { // Chỉ hợp nhất nếu chúng chưa cùng một thành phần
// 1. Trừ đi chi phí của hai thành phần cũ khỏi tổng chi phí
total_min_ops -= get_cost(root_u);
total_min_ops -= get_cost(root_v);
// Ưu tiên hợp nhất vào thành phần có chứa nút cơ sở (k+1) nếu có
if (root_u == find_set(k + 1)) std::swap(root_u, root_v);
// 2. Thực hiện hợp nhất: nối gốc của u vào gốc của v
parent[root_u] = root_v;
// Cập nhật trọng số cho cạnh nối mới này
val[root_u] = required_xor;
// 3. Cập nhật kích thước cho thành phần mới (tại root_v)
if (required_xor == 0) { // Nếu giá trị(root_u) == giá trị(root_v)
sz[root_v][0] += sz[root_u][0];
sz[root_v][1] += sz[root_u][1];
} else { // Nếu giá trị(root_u) != giá trị(root_v)
sz[root_v][0] += sz[root_u][1];
sz[root_v][1] += sz[root_u][0];
}
// 4. Cộng chi phí của thành phần mới vào tổng chi phí
total_min_ops += get_cost(root_v);
}
}
int main() {
// Tăng tốc độ nhập xuất
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
// Đọc dữ liệu đầu vào
std::cin >> n >> k;
std::cin >> s;
for (int i = 1; i <= k; ++i) {
int c; // Số lượng đèn trong tập hợp
std::cin >> c;
for (int j = 0; j < c; ++j) {
int x; // Chỉ số của bóng đèn
std::cin >> x;
bulb_to_sets[x].push_back(i);
}
}
// Khởi tạo DSU cho k tập hợp và 1 nút cơ sở (k+1)
for (int i = 1; i <= k + 1; ++i) {
parent[i] = i; // Ban đầu, mỗi nút là gốc của chính nó
val[i] = 0; // Khoảng cách XOR đến cha (chính nó) là 0
sz[i][0] = 1; // Thành phần có 1 nút, có giá trị CÙNG gốc
sz[i][1] = 0; // Thành phần có 0 nút, có giá trị KHÁC gốc
}
// Xử lý lần lượt các bóng đèn từ 1 đến n
for (int i = 1; i <= n; ++i) {
// target là giá trị XOR cần có để đèn i bật
// Nếu s[i-1] là '0', cần XOR 1. Nếu là '1', cần XOR 0.
int target = 1 - (s[i - 1] - '0');
if (bulb_to_sets[i].size() == 1) {
// Trường hợp 1: Đèn i chỉ thuộc 1 tập hợp A_p
// Ràng buộc: giá trị(p) = target <=> giá trị(p) ^ giá trị(cơ sở) = target
int set_idx = bulb_to_sets[i][0];
unite_sets(set_idx, k + 1, target);
} else if (bulb_to_sets[i].size() == 2) {
// Trường hợp 2: Đèn i thuộc 2 tập hợp A_p và A_q
// Ràng buộc: giá trị(p) ^ giá trị(q) = target
int set1_idx = bulb_to_sets[i][0];
int set2_idx = bulb_to_sets[i][1];
unite_sets(set1_idx, set2_idx, target);
}
// In ra kết quả cho i đèn đầu tiên
std::cout << total_min_ops << "\n";
}
return 0;
}