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

#define rep(i, n) for(int i = 0; i < (n); ++i)
#define repA(i, a, n) for(int i = a; i <= (n); ++i)
#define repD(i, a, n) for(int i = a; i >= (n); --i)
#define trav(a, x) for(auto& a : x)
#define all(x) x.begin(), x.end()
#define sz(x) (int)(x).size()
#define fill(a) memset(a, 0, sizeof (a))
#define fst first
#define snd second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;

const int maxc = 400019;
vector <set <pii>> c(maxc);

int main() {
	cin.sync_with_stdio(0); cin.tie(0);
	cin.exceptions(cin.failbit);
	int n; cin >> n;
	vi a(n), b(n); rep(i,n) cin >> a[i] >> b[i];
	int ans = 0;
	rep(i,n) c[a[i]].insert(mp(i,0));
	rep(i,n) c[b[i]].insert(mp(i,1));
	queue <int> que; 
	rep(i,maxc){
		if(sz(c[i]) == 1) que.push(i);
	}
	while(!que.empty()){
		int f = que.front();
		que.pop();
		if(sz(c[f])){
			ans++;
			pii aa = *c[f].begin();
			c[f].erase(aa);
			aa.snd = 1 - aa.snd;
			int ff = (aa.snd == 0) ? a[aa.fst] : b[aa.fst];
			c[ff].erase(aa);
			if(sz(c[ff]) == 1) que.push(ff);
		}
	}
	rep(i,maxc){
		if(sz(c[i])) ans++;
	}
	cout << ans << endl;


	return 0;
}


#include<bits/stdc++.h>
#define pi 3.141592653589793238
#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")
#define MOD 1000000007
#define INF 999999999999999999 
#define pb push_back
#define ff first
#define ss second
 
#define mt make_tuple
#define ll long long
#define fast ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL);
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>

using namespace __gnu_pbds;
 
 
typedef tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update> indexed_set;
 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const int N = 4e5 + 1;
ll parent[N], edges[N], sz[N];
ll findset(ll a){
    if(a == parent[a]){
        return a;
    }
    return parent[a] = findset(parent[a]);
} 
void unionset(ll a, ll b){
    a = findset(a);
    b = findset(b);
    if(a == b){
        edges[a]++;
        return;
    }
    sz[a] += sz[b];
    parent[b] = a;
    edges[a] += edges[b] + 1;
}
int main() {
    //freopen("input.txt", "r", stdin);
    //freopen("output.txt", "w", stdout);
    fast;
    ll T = 1, i, j;
    
    //cin >> T;
    while (T--) {
        ll n;
        cin >> n;
        for(i = 1;  i < N; i++){
            parent[i] = i;
            sz[i] = 1;
        }
        for(i = 0; i < n; i++){
            ll a, b;
            cin >> a >> b;
            if(1){
                unionset(a ,b);
            }
        }
        ll ans = 0;
        set<ll> diffs;
        for(i = 1; i < N; i++){
            diffs.insert(findset(i));
        }
        for(auto i : diffs){
            ans += min(edges[i], sz[i]);
        }
        cout << ans << endl;
    }
    return 0;
}