#include <bits/stdc++.h>
#define int long long
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
using namespace std;
const int MOD = 1000000007;
const int INF = numeric_limits<int>::max() / 2;
typedef pair<int,int> P;
using Graph = vector<vector<int>>;

class UnionFind {
public:
    vector <int> par; // 各元の親を表す配列
    vector <int> siz; // 素集合のサイズを表す配列(1 で初期化)

    // Constructor
    UnionFind(int sz_): par(sz_), siz(sz_, (int)1) {
        for (int i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }
    void init(int sz_) {
        par.resize(sz_);
        siz.assign(sz_, (int)1);
        for (int i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }

    // Member Function
    // Find
    int root(int x) { // 根の検索
        while (par[x] != x) {
            x = par[x] = par[par[x]]; // x の親の親を x の親とする
        }
        return x;
    }

    // Union(Unite, Merge)
    bool merge(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        // merge technique（データ構造をマージするテク．小を大にくっつける）
        if (siz[x] < siz[y]) swap(x, y);
        siz[x] += siz[y];
        par[y] = x;
        return true;
    }

    bool issame(int x, int y) { // 連結判定
        return root(x) == root(y);
    }

    int size(int x) { // 素集合のサイズ
        return siz[root(x)];
    }
};

signed main() {
    int N;
    cin >> N;
    int A[N], B[N];
    UnionFind uf(400010);
    bool ok[400010]{};
    rep(i,N){
        cin >> A[i] >> B[i];
        if(uf.issame(A[i], B[i]) || A[i] == B[i]){
            ok[A[i]] = true;
        }
        else uf.merge(A[i], B[i]);
    }
    rep(i,400005){
        if(ok[i]){
            ok[uf.root(i)] = true;
        }
    }
    int ans = 0;
    rep(i,400005){
        if(ok[i] && uf.size(i) == 1) ++ans;
        else if(uf.size(i) == 1) continue;
        else if(uf.root(i) != i) continue;
        else if(ok[i]) ans += uf.size(i);
        else ans += uf.size(i) - 1;
    }
    cout << ans << endl;
}
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

//#define int		long long
#define pb		push_back
#define ppb		pop_back
#define pf		push_front
#define ppf		pop_front
#define all(x)		(x).begin(),(x).end()
#define uniq(v)		(v).erase(unique(all(v)),(v).end())
#define sz(x)		(int)((x).size())
#define fr		first
#define sc		second
#define pii		pair<int,int>
#define rep(i,a,b)	for(int i=a;i<b;i++)
#define mem1(a)		memset(a,-1,sizeof(a))
#define mem0(a)		memset(a,0,sizeof(a))
#define ppc		__builtin_popcount
#define ppcll		__builtin_popcountll
//#define rep(i, n) for (int i = 0; i < (int)(n); i++)

//template<typename T1,typename T2>istream& opertor>>(istream& in,pair<T1,T2> &a){in>>a.fr>>
//template<typename T1,typename T2>istream& opertor<<(ostream& out,pair<T1,T2> a){out<<a.fr<<
template<typename T,typename T1>T amax(T &a,T1 b){if(b>a)a=b;return a;}
template<typename T,typename T1>T amin(T &a,T1 b){if(b<a)a=b;return a;}
//template<class T> void chmin(T& a, T b){if(a>b)a=b;}
//template<class T> void chmax(T& a, T b){if(a<b)a=b;}

const long long INF=1e18;
const int32_t M=1e9+7;
const int32_t MM=998244353;

void out_vec_with_space(vector<auto> &v){
  for ( int i = 0; i < v.size(); i++ ){
      cout << ( i ? " " : "" ) << v[i];
  }
}

int main() {
  int A,B;
  cin >> A >> B;
  
  vector<int> E_plus(A),E_minus(B);
  rep(i,0,A) {
    E_plus[i] = i+1;
  }
  
  rep(i,0,B) {
    E_minus[i] = -i-1;
  }
  
  if(A<B){
    ll sum_B = 0;
    rep(i,A-1,B){
      sum_B += E_minus[i];
    }
    E_plus[A-1] = -sum_B;
  }else if(B<A){
    ll sum_A = 0;
    rep(i,B-1,A){
      sum_A += E_plus[i];
    }
    E_minus[B-1] = -sum_A;
  }
  
  out_vec_with_space(E_minus);
  cout << " ";
  out_vec_with_space(E_plus);
  cout << endl;
  
}