#include <bits/stdc++.h>

using namespace std;

class Blossom {
    // 1-based vertex index
    vector<int> vis, par, orig, match, aux;
    int t = 0, N;
    vector<vector<int>> conn;
    queue<int> Q;

    void augment(int u, int v) {
        int pv = v, nv;
        do {
            pv = par[v], nv = match[pv];
            match[v] = pv, match[pv] = v;
            v = nv;
        } while (u != pv);
    }
    int lca(int v, int w) {
        ++t;
        while (1) {
            if (v) {
                if (aux[v] == t) {
                    return v;
                }
                aux[v] = t;
                v = orig[par[match[v]]];
            }
            swap(v, w);
        }
    }

    void blossom(int v, int w, int a) {
        while (orig[v] != a) {
            par[v] = w;
            w = match[v];
            if (vis[w] == 1) {
                Q.push(w), vis[w] = 0;
            }
            orig[v] = orig[w] = a;
            v = par[w];
        }
    }

    bool bfs(int u) {
        vis.assign(N + 1, -1);
        iota(orig.begin(), orig.end(), 0);
        Q = queue<int>();
        Q.push(u);
        vis[u] = 0;
        while (Q.size()) {
            int v = Q.front();
            Q.pop();
            for (int x : conn[v]) {
                if (vis[x] == -1) {
                    par[x] = v;
                    vis[x] = 1;
                    if (!match[x]) {
                        return augment(u, x), true;
                    }
                    Q.push(match[x]);
                    vis[match[x]] = 0;
                } else if (vis[x] == 0 && orig[v] != orig[x]) {
                    int a = lca(orig[v], orig[x]);
                    blossom(x, v, a);
                    blossom(v, x, a);
                }
            }
        }
        return false;
    }

public:
    Blossom(int n) : vis(n + 1), par(n + 1), orig(n + 1), match(n + 1), aux(n + 1), N(n), conn(n + 1) {}

    void addEdge(int u, int v) {
        assert(1 <= u && u <= N && 1 <= v && v <= N);
        conn[u].push_back(v);
        conn[v].push_back(u);
    }

    int Match() {
        int ans = 0;
        vector<int> V(N - 1);
        iota(V.begin(), V.end(), 1);
        shuffle(V.begin(), V.end(), mt19937(chrono::steady_clock::now().time_since_epoch().count()));
        for (int x : V) {
            if (!match[x]) {
                for (int y : conn[x]) {
                    if (!match[y]) {
                        match[x] = y;
                        match[y] = x;
                        ++ans;
                        break;
                    }
                }
            }
        }
        for (int i = 1; i <= N; i++) {
            if (!match[i] && bfs(i)) ++ans;
        }
        return ans;
    }
};

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> cnt(n + 1);
    vector<vector<int>> line(m);
    for (int i = 0; i < m; i++) {
        int k;
        cin >> k;
        for (int j = 0; j < k; j++) {
            int a;
            cin >> a;
            cnt[a].emplace_back(i);
            line[i].push_back(a);
        }
    }

    int ans = 0;
    vector<bool> used(m);
    for (int i = 1; i <= n; i++) {
        if (cnt[i].empty()) {
            ans++;
        } else if (cnt[i].size() == 1 && used[cnt[i][0]] == false) {
            ans++;
            used[cnt[i][0]] = true;
        }
    }
    vector<pair<int, int>> es;
    map<int, int> mp;
    for (int i = 1; i <= n; i++) {
        if (cnt[i].size() == 2 && used[cnt[i][0]] == false && used[cnt[i][1]] == false) {
            es.emplace_back(cnt[i][0], cnt[i][1]);
            mp[cnt[i][0]];
            mp[cnt[i][1]];
        }
    }
    int M = 0;
    for (auto &p : mp) {
        p.second = M++;
    }
    if (es.size()) {
        Blossom blossom(M);
        for (auto &e : es) {
            blossom.addEdge(mp[e.first] + 1, mp[e.second] + 1);
        }
        int match = blossom.Match();
        ans += match;
    }
    cout << ans << endl;
}


Measured memory_bytes: 11456