#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>

#define int long long
#define FOR(i,a,b,c) for(int i=a;i<b;i+=c)
#define REV(i,a,b,c) for(int i=a;i>=b;i-=c)
#define all(x) x.begin(),x.end()                   
#define Dhruv main

const int pinf=LLONG_MAX;
const int ninf=LLONG_MIN;
const int mod=1000000007;

using namespace std;
using namespace __gnu_pbds;

typedef tree
<int,null_type,less <int>,rb_tree_tag,tree_order_statistics_node_update>
indexed_set;

typedef tree
<int,null_type,less_equal <int>,rb_tree_tag,tree_order_statistics_node_update>
indexed_multiset;

template <typename T>
istream & operator>>(istream &is, vector<T> &v) {
    for(auto &data:v){
    	is>>data;
    }	
    return is;
}

template <typename T>
ostream & operator<<(ostream &os,const vector<T> &v) {
    for(auto &data:v){
    	os<<data<< " ";
    }	
    return os;
}

vector <vector <int> > adj;
vector <bool> vis;
const int maxn=4e5;

void dfs(int u,int &vn,int &en,int p=-1){

    vis[u]=true;
    vn++;
    for(int v:adj[u]){

    	if(v!=p){

    	    en++;
    	    if(not vis[v]) dfs(v,vn,en,u);
    	}	

    }	

}	

int32_t Dhruv(){
	
    ios_base::sync_with_stdio(0); 
    cin.tie(0);

    int T=1;

	while(T--){
		int n;
		cin>>n;
		adj.resize(maxn);
		vis.resize(maxn,true);

		FOR(i,0,n,1){
		    int a,b;
		    cin>>a>>b;
		    a--,b--;
		    adj[a].push_back(b);
		    adj[b].push_back(a);
		    vis[a]=false;
		    vis[b]=false;
		}
		int ans=0;

		
		FOR(i,0,maxn,1){

			if(not vis[i]){

				int vn=0;
				int en=0;
			    dfs(i,vn,en);
			    if(en==vn-1){
			        ans+=(vn-1);
			    }	
			    else{

			        ans+=vn;
			    }	
			}	

		}

		cout<<ans<< "\n";
		
	}	



    
	#ifdef LOCAL
    	cout<< "Time Elapsed: "<<1.0*clock()/CLOCKS_PER_SEC<< "s\n";
    #endif                                                   
    

    return 0;

}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=200005,INF=1<<30;

struct UF{
    int n;
    vector<int> par,size,edge;
    
    void init(int n_){
        n=n_;
        par.assign(n,-1);
        size.assign(n,1);
        edge.assign(n,0);
        
        for(int i=0;i<n;i++){
            par[i]=i;
        }
    }
    
    int root(int a){
        if(par[a]==a) return a;
        else return par[a]=root(par[a]);
    }
    
    void unite(int a,int b){
        edge[root(a)]++;
        if(root(a)!=root(b)){
            size[root(a)]+=size[root(b)];
            edge[root(a)]+=edge[root(b)];
            par[root(b)]=root(a);
        }
    }
    
    bool check(int a,int b){
        return root(a)==root(b);
    }
};


int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    int N;cin>>N;
    UF uf;
    uf.init(400000);
    
    for(int i=0;i<N;i++){
        int a,b;cin>>a>>b;
        a--;b--;
        uf.unite(a,b);
    }
    
    int ans=0;
    
    for(int i=0;i<400000;i++){
        if(uf.root(i)!=i) continue;
        if(uf.size[i]-1==uf.edge[i]) ans+=uf.edge[i];
        else ans+=uf.size[i];
    }
    
    cout<<ans<<endl;
}

