#include #define rep(i,n) for(int i=(0);i<(n);i++) using namespace std; typedef long long ll; template bool chmax(T &a, const T &b) { if (a bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; } // union-find tree with size(struct) struct UnionFind{ vector par; // 親ノード vector rank; // ランク vector size; // 連結成分のサイズ UnionFind(int n = 1) { init(n); } void init(int n = 1) { par.resize(n); rank.resize(n); size.resize(n); for (int i = 0; i < n; ++i){ par[i] = i; rank[i] = 0; size[i] = 1; } } int find(int x) { if (par[x] == x) return x; int r = find(par[x]); return par[x] = r; } bool issame(int x, int y) { return find(x) == find(y); } bool unite(int x, int y) { x = find(x); y = find(y); if (x == y) return false; if (rank[x] < rank[y]) swap(x, y); if (rank[x] == rank[y]) ++rank[x]; par[y] = x; size[x] += size[y]; return true; } int getSize(int x){ return size[find(x)]; } int getRank(int x){ return rank[find(x)]; } }; int main(){ cin.tie(0); ios::sync_with_stdio(false); int N, M; cin >> N >> M; vector b(N), c(N); rep(i, N) { cin >> b[i] >> c[i]; b[i]--; c[i]--; } int col = 0; map cmap; rep(i, N){ if(cmap.count(c[i]) == 0){ cmap[c[i]] = col; col++; } } UnionFind uf(col); map> bmap; rep(i, N){ if(bmap.count(b[i]) == 0){ bmap[b[i]].push_back(cmap[c[i]]); }else{ uf.unite(bmap[b[i]].back(), cmap[c[i]]); bmap[b[i]].push_back(cmap[c[i]]); } } int box = bmap.size(); set st; rep(i, col) st.insert(uf.find(i)); cout << box - st.size() << endl; }