#include <bits/stdc++.h>
using namespace std;

#define mnto(x, y) x = min(x, (__typeof__(x)) y)
#define mxto(x, y) y = max(x, (__typeof__(x)) y)
#define REP(i, s, e) for (int i = s; i < e; i++)
#define RREP(i, s, e) for (int i = s - 1; i >= e; i--)
typedef long long ll;
#define ALL(_a) _a.begin(), _a.end()
#define pb emplace_back
typedef vector<int> vi;
#define MP make_pair
#define FI first
#define SE second
typedef pair<int, int> ii;
#define MT make_tuple
typedef tuple<int, int, int> iii;

#define INF 1000000005
#define LINF 100000000000000005
#define MOD 1000000007
#define MAXN 200005
#define MAXA 400005

int n;
int in[MAXA];
vector<int> adjList[MAXA];
set<ii> st;
bool erased[MAXA];

int main() {
	scanf("%d", &n);
	REP (i, 0, n) {
		int a, b; scanf("%d%d", &a, &b);
		in[a]++;
		adjList[a].pb(b);
		if (a != b) {
			in[b]++;
			adjList[b].pb(a);
		}
	}
	REP (i, 1, MAXA) {
		if (in[i] == 0) continue;
		st.emplace(in[i], i);
	}
	int ans = 0;
	while (!st.empty()) {
		ii cur = *st.begin(); st.erase(st.begin());
		if (erased[cur.SE]) continue;
		for (int v : adjList[cur.SE]) {
			if (erased[v]) continue;
			st.erase(MP(in[v], v));
			in[v]--;
			if (in[v] > 0) st.emplace(MP(in[v], v));
			break;
		}
		erased[cur.SE] = true;
		ans++;
	}
	printf("%d\n", ans);
	return 0;
}

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=2e5,maxm=4e5;
int n;
int f[maxm+5];
int szp[maxm+5],sze[maxm+5];
int ans;
int find(int x){
	return x==f[x]?x:f[x]=find(f[x]);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=maxm;i++) f[i]=i,szp[i]=1;
	for(int i=1,a,b;i<=n;i++){
		scanf("%d %d",&a,&b);
		int fa=find(a),fb=find(b);
		if(fa==fb) sze[fa]++;
		else{
			f[fb]=fa; szp[fa]+=szp[fb]; sze[fa]+=sze[fb]+1;
		}
	}
	ans=maxm;
	for(int i=1;i<=maxm;i++)
		if(i==find(i))
			if(sze[i]==szp[i]-1) ans--;
	printf("%d\n",ans);
	return 0;
}
