#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100005 * 2;
const ll modulo = 1000000007;

int n;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

int parent[MAXN];
bool is_cycled[MAXN];
int sizes[MAXN];

void dsu_init() {
    for (int i = 0; i < MAXN; ++i) {
        parent[i] = i;
        sizes[i] = 1;
        is_cycled[i] = circle_used[i];
    }
}

int dsu_get(int v) {
    if (parent[v] == v)
        return v;

    return parent[v] = dsu_get(parent[v]);
}

void dsu_union(int a, int b) {
    a = dsu_get(a);
    b = dsu_get(b);

    if (a != b) {
        bool cycled = is_cycled[a] || is_cycled[b];

        if (sizes[a] > sizes[b])
            swap(a, b);

        sizes[b] += sizes[a];
        parent[a] = b;
        is_cycled[a] = is_cycled[b] = cycled;
    }
}

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size == 1 ? 1 : 2);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);

    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));
    dsu_init();

    for (int i = 1; i < MAXN; ++i) {
        for (int to : g[i]) {
            dsu_union(i, to);
        }
    }

    ll ans = 1;
    for (int i = 1; i < MAXN; ++i) {
        if (!is_cycled[dsu_get(i)]) {
            circle_sizes.push_back(sizes[dsu_get(i)]);

            is_cycled[dsu_get(i)] = true;
        }
    }
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100005 * 2;
const ll modulo = 1000000007;

int n;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int final_dfs(int v) {
    used[v] = true;

    int ans = 1;
    for (int to : g[v]) {
        if (circle_used[to])
            return -1;

        if (!used[to] && !circle_used[to]) {
            int t = final_dfs(to);
            if (t == -1)
                return -1;

            ans += t;
        }
    }

    for (int to : gt[v]) {
        if (circle_used[to])
            return -1;

        if (!used[to] && !circle_used[to]) {
            int t = final_dfs(to);
            if (t == -1)
                return -1;

            ans += t;
        }
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i] && !circle_used[i]) {
            int t = final_dfs(i);

            if (t == -1) {
                continue;
            }

            circle_sizes.push_back(t);
        }
    }

    ll ans = 1;
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100005 * 2;
const ll modulo = 1000000007;

int n;

vector<int> g[MAXN];
bool cycle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

int parent[MAXN];
int sizes[MAXN];

void dsu_init() {
    for (int i = 0; i < MAXN; ++i) {
        parent[i] = i;
        sizes[i] = 1;
    }
}

int dsu_get(int v) {
    if (parent[v] == v)
        return v;

    return parent[v] = dsu_get(parent[v]);
}

void dsu_union(int a, int b) {
    a = dsu_get(a);
    b = dsu_get(b);

    if (a != b) {
        bool cycled = cycle_used[a] || cycle_used[b];

        if (sizes[a] > sizes[b])
            swap(a, b);

        sizes[b] += sizes[a];
        parent[a] = b;
        cycle_used[a] = cycle_used[b] = cycled;
    }
}

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                cycle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            cycle_used[to] = true;

            circle_sizes.push_back(circle_size == 1 ? 1 : 2);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);

    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));
    dsu_init();

    for (int i = 1; i < MAXN; ++i) {
        for (int to : g[i]) {
            dsu_union(i, to);
        }
    }

    ll ans = 1;
    for (int i = 1; i < MAXN; ++i) {
        int x = dsu_get(i);
        if (!cycle_used[x]) {
            circle_sizes.push_back(sizes[x]);

            cycle_used[x] = true;
        }
    }
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100005 * 2;
const ll modulo = 1000000007;

int n;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int final_dfs(int v) {
    used[v] = true;

    int ans = 1;
    for (int to : g[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    for (int to : gt[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i] && !circle_used[i])
            circle_sizes.push_back(final_dfs(i));
    }

    ll ans = 1;
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 200000;
const ll modulo = 1e9 + 7;

int n;
ll ans;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int final_dfs(int v) {
    used[v] = true;

    int ans = 1;
    for (int to : g[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    for (int to : gt[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i] && !circle_used[i])
            circle_sizes.push_back(final_dfs(i));
    }

    ll ans = 1;
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100005 * 2;
const ll modulo = 1000000007;

int n;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size == 1 ? 1 : 2);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int final_dfs(int v) {
    used[v] = true;

    int ans = 1;
    for (int to : g[v]) {
        if (circle_used[to])
            return -1;

        if (!used[to] && !circle_used[to]) {
            int t = final_dfs(to);
            if (t == -1)
                return -1;

            ans += t;
        }
    }

    for (int to : gt[v]) {
        if (circle_used[to])
            return -1;

        if (!used[to] && !circle_used[to]) {
            int t = final_dfs(to);
            if (t == -1)
                return -1;

            ans += t;
        }
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i] && !circle_used[i]) {
            int t = final_dfs(i);

            if (t == -1) {
                continue;
            }

            circle_sizes.push_back(t);
        }
    }

    ll ans = 1;
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


#include <array>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#include <random>
#include <climits>
#include <stack>
#include <set>

using namespace std;

typedef long long ll;
typedef long double ld;

const int MAXN = 100;
const ll modulo = 1e9 + 7;

int n;
ll ans;

vector<int> g[MAXN];
vector<int> gt[MAXN];
bool circle_used[MAXN];
bool used[MAXN];

vector<int> path;
set<int> st_path;

vector<int> circle_sizes;

void find_and_delete_circles(int v) {
    used[v] = true;
    path.push_back(v);
    st_path.insert(v);

    for (int to : g[v]) {
        if (!used[to]) {
            find_and_delete_circles(to);
        }
        else {
            if (st_path.find(to) == st_path.end())
                continue;

            int circle_size = 0;
            //! cicle detected
            for (size_t i = path.size() - 1; path[i] != to; --i) {
                circle_used[path[i]] = true;
                ++circle_size;
            }

            ++circle_size;
            circle_used[to] = true;

            circle_sizes.push_back(circle_size);
        }
    }

    st_path.erase(v);
    path.pop_back();
}

int final_dfs(int v) {
    used[v] = true;

    int ans = 1;
    for (int to : g[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    for (int to : gt[v]) {
        if (!used[to] && !circle_used[to])
            ans += final_dfs(to);
    }

    return ans;
}

int main() {
    ios::sync_with_stdio(0);
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
    cin >> n;
    for (int i = 0; i < n; ++i) {
        int x, y;
        cin >> x >> y;

        g[x].push_back(y);
        gt[y].push_back(x);
    }

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i])
            find_and_delete_circles(i);
    }

    memset(used, 0, sizeof(used));

    for (int i = 1; i < MAXN; ++i) {
        if (!used[i] && !circle_used[i])
            circle_sizes.push_back(final_dfs(i));
    }

    ll ans = 1;
    for (int x : circle_sizes) {
        ans = ans * x % modulo;
    }

    cout << ans;

    return 0;
}


//In the name of God B-)	:Alikhm
#include <bits/stdc++.h>
#define pb push_back
#define po pop_back
#define ins insert
#define co continue
#define rp(i,n)	for(int i=0;i<n;++i)
#define rrp(i,n)	for(int i=1;i<=n;++i)
#define db(a,b,c)	cout<<a<<" "<<b<<" "<<c<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const LL MAXN=2e5+1,INF=1e17,MOD=1e9+7,MODH=999998727899999ll;

LL n,ans[MAXN],Ans=1,p[MAXN],sz[MAXN];
LL root(LL u){
    if(p[u]==u) return u;
    return(p[u]=root(p[u]));
}
set <LL> se;
int main()
{
	ios_base::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=2*n;++i){p[i]=i;sz[i]=1;ans[i]=1;se.ins(i);}
	for(int i=0;i<n;++i){
        LL a,b;
        cin>>a>>b;
        if(a==b){ans[root(a)]=-1;continue;}
        if((a=(root(a)))==(b=(root(b)))){if(ans[a]!=-1)ans[a]=-2;continue;}
        if(sz[a]>sz[b]) swap(a,b);
        sz[b]+=sz[a];
        if(ans[b]!=-1&&ans[b]!=-2)ans[b]=sz[b];
        p[a]=b;
        se.erase(a);
	}
	while(se.size()){
        LL x=*se.begin();
        se.erase(x);
        //cout<<"h"<<endl;
        if(ans[x]!=-1&&ans[x]!=-2)    Ans=(Ans*ans[x])%MOD;
        else if(ans[x]==-2) Ans=(Ans*2)%MOD;
	}
	cout<<Ans<<endl;
	return 0;
}


//In the name of God B-)	:Alikhm
#include <bits/stdc++.h>
#define pb push_back
#define po pop_back
#define ins insert
#define co continue
#define rp(i,n)	for(int i=0;i<n;++i)
#define rrp(i,n)	for(int i=1;i<=n;++i)
#define db(a,b,c)	cout<<a<<" "<<b<<" "<<c<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const LL MAXN=2e5+1,INF=1e17,MOD=1e9+7,MODH=999998727899999ll;

LL n,ans[MAXN],Ans=1,p[MAXN],sz[MAXN];
int root(int u){
    if(p[u]==u) return u;
    return(p[u]=root(p[u]));
}
set <int> se;
int main()
{
	ios_base::sync_with_stdio(0);
	cin>>n;for(int i=1;i<=2*n;++i){p[i]=i;sz[i]=1;ans[i]=1;se.ins(i);}
	for(int i=0;i<n;++i){
        int a,b;
        cin>>a>>b;
        if(a!=b&&(a=(root(a)))==(b=(root(b)))){ans[a]=2;continue;}
        if(sz[a]>sz[b]) swap(a,b);
        sz[b]+=sz[a];
        ans[b]=sz[b];
        p[a]=b;
        se.erase(a);
	}
	while(se.size()){
        int x=*se.begin();
        se.erase(x);
        //cout<<"h"<<endl;
        Ans=(Ans*ans[x])%MOD;
	}
	cout<<Ans<<endl;
	return 0;
}


//In the name of God B-)	:Alikhm
#include <bits/stdc++.h>
#define pb push_back
#define po pop_back
#define ins insert
#define co continue
#define rp(i,n)	for(int i=0;i<n;++i)
#define rrp(i,n)	for(int i=1;i<=n;++i)
#define db(a,b,c)	cout<<a<<" "<<b<<" "<<c<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const LL MAXN=2e5+1,INF=1e17,MOD=1e9+7,MODH=999998727899999ll;

LL n,ans[MAXN],Ans=1,p[MAXN],sz[MAXN];
LL root(LL u){
    if(p[u]==u) return u;
    return(p[u]=root(p[u]));
}
set <LL> se;
int main()
{
	ios_base::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=2*n;++i){p[i]=i;sz[i]=1;ans[i]=3;se.ins(i);}
	for(int i=0;i<n;++i){
        LL a,b;
        cin>>a>>b;
        if(a==b){ans[root(a)]=1;continue;}
        if((a=(root(a)))==(b=(root(b)))){ans[a]=2;continue;}
        if(sz[a]>sz[b]) swap(a,b);
        sz[b]+=sz[a];
        if(ans[a]==1)   ans[b]=1;
        else if(ans[a]==2)   ans[b]=2;
        p[a]=b;
        se.erase(a);
        //cout<<ans[b]<<"*"<<b<<endl;
	}
	while(se.size()){
        LL x=*se.begin();
        se.erase(x);
        //cout<<x<<" "<<ans[x]<<endl;
        if(ans[x]==3)    Ans=(Ans*sz[x])%MOD;
        else if(ans[x]==2) Ans=(Ans*2)%MOD;
	}
	cout<<Ans<<endl;
	return 0;
}


//In the name of God B-)	:Alikhm
#include <bits/stdc++.h>
#define pb push_back
#define po pop_back
#define ins insert
#define co continue
#define rp(i,n)	for(int i=0;i<n;++i)
#define rrp(i,n)	for(int i=1;i<=n;++i)
#define db(a,b,c)	cout<<a<<" "<<b<<" "<<c<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const LL MAXN=2e5+1,INF=1e17,MOD=1e9+7,MODH=999998727899999ll;

LL n,ans[MAXN],Ans=1,p[MAXN],sz[MAXN];
int root(int u){
    if(p[u]==u) return u;
    return(p[u]=root(p[u]));
}
set <int> se;
int main()
{
	ios_base::sync_with_stdio(0);
	cin>>n;for(int i=1;i<=2*n;++i){p[i]=i;sz[i]=1;ans[i]=1;se.ins(i);}
	for(int i=0;i<n;++i){
        int a,b;
        cin>>a>>b;
        if(a==b){ans[root(a)]=-1;continue;}
        if((a=(root(a)))==(b=(root(b)))){ans[a]=2;continue;}
        if(sz[a]>sz[b]) swap(a,b);
        sz[b]+=sz[a];
        if(ans[b]!=-1)ans[b]=sz[b];
        p[a]=b;
        se.erase(a);
	}
	while(se.size()){
        int x=*se.begin();
        se.erase(x);
        //cout<<"h"<<endl;
        if(ans[x]!=-1)    Ans=(Ans*ans[x])%MOD;
	}
	cout<<Ans<<endl;
	return 0;
}


//In the name of God B-)	:Alikhm
#include <bits/stdc++.h>
#define pb push_back
#define po pop_back
#define ins insert
#define co continue
#define rp(i,n)	for(int i=0;i<n;++i)
#define rrp(i,n)	for(int i=1;i<=n;++i)
#define db(a,b,c)	cout<<a<<" "<<b<<" "<<c<<endl
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const LL MAXN=2e5+1,INF=1e17,MOD=1e9+7,MODH=999998727899999ll;

LL n,ans[MAXN],Ans=1,p[MAXN],sz[MAXN];
LL root(LL u){
    if(p[u]==u) return u;
    return(p[u]=root(p[u]));
}
set <LL> se;
int main()
{
	ios_base::sync_with_stdio(0);
	cin>>n;for(int i=1;i<=2*n;++i){p[i]=i;sz[i]=1;ans[i]=1;se.ins(i);}
	for(int i=0;i<n;++i){
        LL a,b;
        cin>>a>>b;
        if(a==b){ans[root(a)]=-1;continue;}
        if((a=(root(a)))==(b=(root(b)))){ans[a]=2;continue;}
        if(sz[a]>sz[b]) swap(a,b);
        sz[b]+=sz[a];
        if(ans[b]!=-1)ans[b]=sz[b];
        p[a]=b;
        se.erase(a);
	}
	while(se.size()){
        LL x=*se.begin();
        se.erase(x);
        //cout<<"h"<<endl;
        if(ans[x]!=-1)    Ans=(Ans*ans[x])%MOD;
	}
	cout<<Ans<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#ifndef d
#define d(...)
#endif
#define st first
#define nd second
#define pb push_back
#define siz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()
typedef long long LL;

const int mod=1e9+7;

vector< pair<int,bool> >graf[200005];
int deg[200005];
int visited[200005];
int n;
LL wynik=1;

vector< vector<int> >spojne;

void dfs(int a)
{
	visited[a]=1;
	spojne.back().pb(a);
	for(auto p:graf[a])
		if(!visited[p.st])
			dfs(p.st);
}

void toposort(int a)
{
	if(siz(spojne[a])==1)
		return;
	queue<int>q;
	int cnt=0;
	for(auto b:spojne[a])
		if(!deg[b])
			q.push(b);
	while(!q.empty())
	{
		int w=q.front();
		q.pop();
		cnt++;
		for(auto p:graf[w])
		{
			if(p.nd)
				if(--deg[p.st]==0)
					q.push(p.st);
		}
	}
	if(cnt==siz(spojne[a])){
		wynik*=cnt;
		wynik%=mod;
	}
	else{
		wynik*=2;
		wynik%=mod;
	}
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin>>n;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		graf[a].pb({b,1});
		graf[b].pb({a,0});
		deg[b]++;
	}
	for(int i=1;i<=2*n;i++)
		if(!visited[i] && !graf[i].empty()){
			spojne.pb(vector<int>());
			dfs(i);
		}
	for(int i=0;i<siz(spojne);i++)
		toposort(i);

	cout<<wynik<<"\n";

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#ifndef d
#define d(...)
#endif
#define st first
#define nd second
#define pb push_back
#define siz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()
typedef long long LL;

const int mod=1e9+7;

vector< pair<int,bool> >graf[100005];
int deg[100005];
int visited[100005];
int n;
LL wynik=1;

vector< vector<int> >spojne;

void dfs(int a)
{
	visited[a]=1;
	spojne.back().pb(a);
	for(auto p:graf[a])
		if(!visited[p.st])
			dfs(p.st);
}

void toposort(int a)
{
	if(siz(spojne[a])==1)
		return;
	queue<int>q;
	int cnt=0;
	for(auto b:spojne[a])
		if(!deg[b])
			q.push(b);
	while(!q.empty())
	{
		int w=q.front();
		q.pop();
		cnt++;
		for(auto p:graf[w])
		{
			if(p.nd)
				if(--deg[p.st]==0)
					q.push(p.st);
		}
	}
	if(cnt==siz(spojne[a])){
		wynik*=cnt;
		wynik%=mod;
	}
	else{
		wynik*=2;
		wynik%=mod;
	}
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin>>n;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		graf[a].pb({b,1});
		graf[b].pb({a,0});
		deg[b]++;
	}
	for(int i=1;i<=2*n;i++)
		if(!visited[i] && !graf[i].empty()){
			spojne.pb(vector<int>());
			dfs(i);
		}
	for(int i=0;i<siz(spojne);i++)
		toposort(i);

	cout<<wynik<<"\n";

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#ifndef d
#define d(...)
#endif
#define st first
#define nd second
#define pb push_back
#define siz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()
typedef long long LL;

const int mod=1e9+7;

vector< pair<int,bool> >graf[200005];
int deg[200005];
int visited[200005];
int n;
LL wynik=1;

vector< vector<int> >spojne;

void dfs(int a)
{
	visited[a]=1;
	spojne.back().pb(a);
	for(auto p:graf[a])
		if(!visited[p.st])
			dfs(p.st);
}

void toposort(int a)
{
	if(siz(spojne[a])==1)
		return;
	queue<int>q;
	int cnt=0;
	for(auto b:spojne[a])
		if(!deg[b])
			q.push(b);
	while(!q.empty())
	{
		int w=q.front();
		q.pop();
		cnt++;
		for(auto p:graf[w])
		{
			if(p.nd){
				if(--deg[p.st]==0)
					q.push(p.st);
				if(p.st==w)
					return;
			}
		}
	}
	if(cnt==siz(spojne[a])){
		wynik*=cnt;
		wynik%=mod;
	}
	else{
		wynik*=2;
		wynik%=mod;
	}
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin>>n;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		graf[a].pb({b,1});
		graf[b].pb({a,0});
		deg[b]++;
	}
	for(int i=1;i<=2*n;i++)
		if(!visited[i] && !graf[i].empty()){
			spojne.pb(vector<int>());
			dfs(i);
		}
	for(int i=0;i<siz(spojne);i++)
		toposort(i);

	cout<<wynik<<"\n";

	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#ifndef d
#define d(...)
#endif
#define st first
#define nd second
#define pb push_back
#define siz(c) (int)(c).size()
#define all(c) (c).begin(), (c).end()
typedef long long LL;

const int mod=1e9+7;

vector< pair<int,bool> >graf[200005];
int deg[200005];
int visited[200005];
int n;
LL wynik=1;

vector< vector<int> >spojne;

void dfs(int a)
{
	visited[a]=1;
	spojne.back().pb(a);
	for(auto p:graf[a])
		if(!visited[p.st])
			dfs(p.st);
}

void toposort(int a)
{
	if(siz(spojne[a])==1)
		return;
	queue<int>q;
	int cnt=0;
	for(auto b:spojne[a])
		if(!deg[b])
			q.push(b);
	while(!q.empty())
	{
		int w=q.front();
		q.pop();
		cnt++;
		for(auto p:graf[w])
		{
			if(p.nd){
				if(--deg[p.st]==0)
					q.push(p.st);
			}
		}
	}
	if(cnt==siz(spojne[a])){
		wynik*=cnt;
		wynik%=mod;
	}
	else if(cnt!=siz(spojne[a])-1){
		wynik*=2;
		wynik%=mod;
	}
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);

	cin>>n;
	for(int i=0;i<n;i++)
	{
		int a,b;
		cin>>a>>b;
		graf[a].pb({b,1});
		graf[b].pb({a,0});
		deg[b]++;
	}
	for(int i=1;i<=2*n;i++)
		if(!visited[i] && !graf[i].empty()){
			spojne.pb(vector<int>());
			dfs(i);
		}
	for(int i=0;i<siz(spojne);i++)
		toposort(i);

	cout<<wynik<<"\n";

	return 0;
}


#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdlib>
#include <limits>
#include <iostream>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <random>
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;

#define gc getchar unlocked
#ifndef ONLINE JUDGE
#define gc getchar
#endif // ONLINE JUDGE

#define pc putchar_unlocked
#ifndef ONLINE JUDGE
#define pc putchar
#endif // ONLINE JUDGE

#define fRead           freopen("input.txt","r",stdin)
#define fWrite          freopen("output.txt","w",stdout)

#define eps             1e-9
#define inf             0x3f3f3f3f
#define INF             2e18
#define LL              long long
#define ULL             unsigned long long
#define PI              acos(-1.0)
#define pb              push_back
#define mk              make_pair
#define pii             pair<int,int>
#define pLL             pair<LL,LL>
#define ff              first
#define ss              second
#define all(a)          a.begin(),a.end()
#define rall(a)         a.rbegin(),a.rend()
#define SQR(a)          ((a)*(a))
#define Unique(a)       sort(all(a)),a.erase(unique(all(a)),a.end())
#define min3(a,b,c)     min(a,min(b,c))
#define max3(a,b,c)     max(a,max(b,c))
#define min4(a,b,c,d)   min(min(a,b),min(c,d))
#define max4(a,b,c,d)   max(max(a,b),max(c,d))
#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))
#define Iterator(a)     __typeof__(a.begin())
#define rIterator(a)    __typeof__(a.rbegin())
#define FOR(a,it)       for(Iterator(a) it = a.begin();it != a.end(); it++)
#define rFOR(a,it)      for(rIterator(a) it = a.rbegin();it != a.rend(); it++)
#define FastRead        ios_base::sync_with_stdio(0);cin.tie(0)
#define CasePrint       pc('C'); pc('a'); pc('s'); pc('e'); pc(' '); write(qq++,false); pc(':'); pc(' ')
#define vi              vector <int>
#define vL              vector <LL>
#define For(I,A,B)      for(int I = (A); I  < (B); ++I)
#define rFor(I,A,B)     for(int I = (A); I >= (B); --I)
#define Rep(I,N)        For(I,0,N)
#define REP(I,N)        For(I, 1, N + 1)
#define gti             int, vi, greater<int>
#define gtL             LL, vL, greater<LL>
#define Found(a, b)     a.find(b) != a.end()
#define y0              y00

const int MOD = 1e9 + 7;
int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//template <typename T> using orderset = tree <T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; // find_by_order, order_of_key
template <typename T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }
template <typename T> inline T GCD (T a,T b ) {a = abs(a);b = abs(b); if(a < b) swap(a, b); while ( b ) { a = a % b; swap ( a, b ); } return a;}
template <typename T> inline T EGCD(T a,T b,T &x,T &y){if(a == 0) {x = 0;y = 1;return b;}T x1, y1;T d = EGCD(b % a, a, x1, y1);x = y1 - (b / a) * x1;y = x1;return d;}
template <typename T> inline T LCM(T x,T y){T tp = GCD(x,y);if( (x / tp) * 1. * y > 9e18) return 9e18;return (x / tp) * y;}
template <typename T> inline T BigMod(T A,T B,T M = MOD){T ret = 1;while(B){if(B & 1) ret = (ret * A) % M;A = (A * A) % M;B = B >> 1;}return ret;}
template <typename T> inline T InvMod (T A,T M = MOD){return BigMod(A,M-2,M);}
template <typename T> void Compress(T * in, int n){vector <T> vv;for(int i = 0; i < n; i++) vv.pb(in[i]);Unique(vv);for(int i = 0; i < n; i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
//template <typename T> void Compress(vector <T> &in){vector <T> vv;for(T x : in) vv.pb(x);Unique(vv);for(int i = 0; i < in.size(); i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
/*---------------------------fast I/O------------------------------------*/
#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
template <typename T> T scani(T &n){n = 0;bool negative = false;char c = gc();while( c < '0' || c > '9'){if(c == '-') negative = true;c = gc();}while(c >= '0' && c <= '9'){n = n*10 + c-48;c = gc();}if(negative) n = ~(n-1);return n;}
template <typename T> void write(T n,int type = true){if(n<0) {pc('-');n = -n;}if(!n) {pc('0');if(type==32) pc(' '); else if(type) pc('\n'); return;}char buff[22];int len = 0;while(n) buff[len++] = n%10+48,n/=10;for(int i=len-1;i>=0;i--) pc(buff[i]);if(type==32) pc(' '); else if(type) pc('\n');}
int scans(char *a){int i=0;char c = 0;while(c < 33) c = gc();while(c > 33){a[i++] = c;c = gc();}a[i] = 0;return i;}
/*********************************************** End of template *********************************************/
#define Sieve

#ifdef Sieve
const int pSz = 2000006;
bool np[pSz + 10]; vi prime; int prime_size;void sieve(){np[0] = np[1] = 1;prime.pb(2);for(LL i = 4; i <= pSz; i+=2) np[i] = 1;for(LL i = 3; i <= pSz; i+=2){if(!np[i]){prime.pb(i);for(LL j = i * i; j <= pSz; j += (i << 1)) np[j] = 1;}}prime_size = prime.size();}
#endif

#ifdef Combi
const int nSz = 2000006;
LL F[nSz + 1], tMod = MOD;
void Factorial(){ F[0] = 1; for(int i = 1; i <= nSz; i++) F[i] = (F[i - 1] * i) % tMod; }
inline LL nCr(int n, int r) { return (F[n] * InvMod((F[n - r] * F[r]) % tMod, tMod)) % tMod; }
#endif

#ifdef Z_Algo
void zAlgo(char *s, int *z){
    int L, R, sz; sz = strlen(s); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(string &s, int *z){
    int L, R, sz; sz = s.size(); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(int *s, int *z, int n){
    int L, R, sz; sz = n; z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}
#endif // Z_Algo

/********************************************* define Template *************************************************/

template <typename T> inline T SqrDis(T x1, T y1, T x2, T y2){return SQR(x1 - x2) + SQR(y1 - y2);}
template <typename T> inline T Area2(T Ax, T Ay, T Bx, T By, T Cx, T Cy){T ret = Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By);
    if(ret < 0) return ret = -ret;
    return ret;
}
/**************************************************** GEO ******************************************************/
const int N = 400005; /** need to update this **/
const int M = 44444;
const ULL hs = 3797;
/** use data types carefully try to take 'long long' **/

LL D[N], n;
vi G[N], rG[N];
pii in[N];
LL cnt[N];
LL vs[N], same[N], cycle, res = 1, samStal, sub[N];
LL stk[N], id;

void TPS(int x) {
    vs[x] = 1;
    for(int y : rG[x]) if(vs[y] == 0) TPS(y);
    stk[++id] = x;
}

//void DFS(int x) {
//    if(same[x]) samStal = 1;
//    if(vs[x]) {
//        cycle = 1;
//        return ;
//    }
//
//    sub[x] = 1;
//    vs[x] = 1;
//    for(int y : rG[y]) {
//        DFS(y);
//        sub[x] += sub[y];
//    }
//}

int DFS(int x)
{
   if(same[x] == 1) samStal = 1;
   if(vs[x] == 1){
      cycle = 1;
      return 0;
   }
   vs[x] = 1;
   int ret = 1;
   for(int i : rG[x]) ret += DFS(i);
   return ret;
}

int main()
{
//    FastRead;
//    D[0] = 1;
//    D[1] = 0;
//    for(int i = 2; i < N; i++) D[i] = (D[i - 1] * (i - 1) % MOD + D[i - 2] * (i - 1) % MOD) % MOD;
    cin >> n;
    Rep(i, n) {
        int x , y;
        cin >> x >> y;
        G[x].pb(y);
        rG[y].pb(x);
        same[x] = (x == y);
    }
//    cout << "what\n";
    for(int i = 1; i < 2 * n + 1; i++) if(!vs[i]) TPS(i);
//    cout << "here\n";
    memset(vs, 0, sizeof vs);
    for(int i = id; i ; i--) {
        int x = stk[i];
//        cout << "prpb " << x  << '\n';
        if(vs[x]) continue;
        cycle = samStal = 0;
        LL ml = DFS(x);
//        cout << x << ' ' << cycle << ' ' << samStal << '\n';
        if(samStal == 0) {
            if(cycle) ml = 2;
        }
        else ml = 1;
        res = (res * ml) % MOD;
    }
    cout << res << "\n";
}


#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdlib>
#include <limits>
#include <iostream>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <random>
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;

#define gc getchar unlocked
#ifndef ONLINE JUDGE
#define gc getchar
#endif // ONLINE JUDGE

#define pc putchar_unlocked
#ifndef ONLINE JUDGE
#define pc putchar
#endif // ONLINE JUDGE

#define fRead           freopen("input.txt","r",stdin)
#define fWrite          freopen("output.txt","w",stdout)

#define eps             1e-9
#define inf             0x3f3f3f3f
#define INF             2e18
#define LL              long long
#define ULL             unsigned long long
#define PI              acos(-1.0)
#define pb              push_back
#define mk              make_pair
#define pii             pair<int,int>
#define pLL             pair<LL,LL>
#define ff              first
#define ss              second
#define all(a)          a.begin(),a.end()
#define rall(a)         a.rbegin(),a.rend()
#define SQR(a)          ((a)*(a))
#define Unique(a)       sort(all(a)),a.erase(unique(all(a)),a.end())
#define min3(a,b,c)     min(a,min(b,c))
#define max3(a,b,c)     max(a,max(b,c))
#define min4(a,b,c,d)   min(min(a,b),min(c,d))
#define max4(a,b,c,d)   max(max(a,b),max(c,d))
#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))
#define Iterator(a)     __typeof__(a.begin())
#define rIterator(a)    __typeof__(a.rbegin())
#define FOR(a,it)       for(Iterator(a) it = a.begin();it != a.end(); it++)
#define rFOR(a,it)      for(rIterator(a) it = a.rbegin();it != a.rend(); it++)
#define FastRead        ios_base::sync_with_stdio(0);cin.tie(0)
#define CasePrint       pc('C'); pc('a'); pc('s'); pc('e'); pc(' '); write(qq++,false); pc(':'); pc(' ')
#define vi              vector <int>
#define vL              vector <LL>
#define For(I,A,B)      for(int I = (A); I  < (B); ++I)
#define rFor(I,A,B)     for(int I = (A); I >= (B); --I)
#define Rep(I,N)        For(I,0,N)
#define REP(I,N)        For(I, 1, N + 1)
#define gti             int, vi, greater<int>
#define gtL             LL, vL, greater<LL>
#define Found(a, b)     a.find(b) != a.end()
#define y0              y00

const int MOD = 1e9 + 7;
int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//template <typename T> using orderset = tree <T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; // find_by_order, order_of_key
template <typename T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }
template <typename T> inline T GCD (T a,T b ) {a = abs(a);b = abs(b); if(a < b) swap(a, b); while ( b ) { a = a % b; swap ( a, b ); } return a;}
template <typename T> inline T EGCD(T a,T b,T &x,T &y){if(a == 0) {x = 0;y = 1;return b;}T x1, y1;T d = EGCD(b % a, a, x1, y1);x = y1 - (b / a) * x1;y = x1;return d;}
template <typename T> inline T LCM(T x,T y){T tp = GCD(x,y);if( (x / tp) * 1. * y > 9e18) return 9e18;return (x / tp) * y;}
template <typename T> inline T BigMod(T A,T B,T M = MOD){T ret = 1;while(B){if(B & 1) ret = (ret * A) % M;A = (A * A) % M;B = B >> 1;}return ret;}
template <typename T> inline T InvMod (T A,T M = MOD){return BigMod(A,M-2,M);}
template <typename T> void Compress(T * in, int n){vector <T> vv;for(int i = 0; i < n; i++) vv.pb(in[i]);Unique(vv);for(int i = 0; i < n; i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
//template <typename T> void Compress(vector <T> &in){vector <T> vv;for(T x : in) vv.pb(x);Unique(vv);for(int i = 0; i < in.size(); i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
/*---------------------------fast I/O------------------------------------*/
#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
template <typename T> T scani(T &n){n = 0;bool negative = false;char c = gc();while( c < '0' || c > '9'){if(c == '-') negative = true;c = gc();}while(c >= '0' && c <= '9'){n = n*10 + c-48;c = gc();}if(negative) n = ~(n-1);return n;}
template <typename T> void write(T n,int type = true){if(n<0) {pc('-');n = -n;}if(!n) {pc('0');if(type==32) pc(' '); else if(type) pc('\n'); return;}char buff[22];int len = 0;while(n) buff[len++] = n%10+48,n/=10;for(int i=len-1;i>=0;i--) pc(buff[i]);if(type==32) pc(' '); else if(type) pc('\n');}
int scans(char *a){int i=0;char c = 0;while(c < 33) c = gc();while(c > 33){a[i++] = c;c = gc();}a[i] = 0;return i;}
/*********************************************** End of template *********************************************/
#define Sieve

#ifdef Sieve
const int pSz = 2000006;
bool np[pSz + 10]; vi prime; int prime_size;void sieve(){np[0] = np[1] = 1;prime.pb(2);for(LL i = 4; i <= pSz; i+=2) np[i] = 1;for(LL i = 3; i <= pSz; i+=2){if(!np[i]){prime.pb(i);for(LL j = i * i; j <= pSz; j += (i << 1)) np[j] = 1;}}prime_size = prime.size();}
#endif

#ifdef Combi
const int nSz = 2000006;
LL F[nSz + 1], tMod = MOD;
void Factorial(){ F[0] = 1; for(int i = 1; i <= nSz; i++) F[i] = (F[i - 1] * i) % tMod; }
inline LL nCr(int n, int r) { return (F[n] * InvMod((F[n - r] * F[r]) % tMod, tMod)) % tMod; }
#endif

#ifdef Z_Algo
void zAlgo(char *s, int *z){
    int L, R, sz; sz = strlen(s); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(string &s, int *z){
    int L, R, sz; sz = s.size(); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(int *s, int *z, int n){
    int L, R, sz; sz = n; z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}
#endif // Z_Algo

/********************************************* define Template *************************************************/

template <typename T> inline T SqrDis(T x1, T y1, T x2, T y2){return SQR(x1 - x2) + SQR(y1 - y2);}
template <typename T> inline T Area2(T Ax, T Ay, T Bx, T By, T Cx, T Cy){T ret = Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By);
    if(ret < 0) return ret = -ret;
    return ret;
}
/**************************************************** GEO ******************************************************/
const int N = 400005; /** need to update this **/
const int M = 44444;
const ULL hs = 3797;
/** use data types carefully try to take 'long long' **/

LL D[N], n;
vi G[N], rG[N];
pii in[N];
LL cnt[N];
LL vs[N], same[N], cycle, res = 1, samStal, sub[N];
LL stk[N], id;

void TPS(int x) {
    vs[x] = 1;
    for(int y : rG[x]) if(vs[y] == 0) TPS(y);
    stk[++id] = x;
}

//void DFS(int x) {
//    if(same[x]) samStal = 1;
//    if(vs[x]) {
//        cycle = 1;
//        return ;
//    }
//
//    sub[x] = 1;
//    vs[x] = 1;
//    for(int y : rG[y]) {
//        DFS(y);
//        sub[x] += sub[y];
//    }
//}

int DFS(int x)
{
   if(same[x] == 1) samStal = 1;
   if(vs[x] == 1){
      cycle = 1;
      return 0;
   }
   vs[x] = 1;
   int ret = 1;
   for(int i : rG[x]) ret += DFS(i);
   return ret;
}

int main()
{
//    FastRead;
//    D[0] = 1;
//    D[1] = 0;
//    for(int i = 2; i < N; i++) D[i] = (D[i - 1] * (i - 1) % MOD + D[i - 2] * (i - 1) % MOD) % MOD;
    cin >> n;
    Rep(i, n) {
        int x , y;
        cin >> x >> y;
        G[x].pb(y);
        rG[y].pb(x);
        same[x] = (x == y);
    }
//    cout << "what\n";
    for(int i = 1; i < 2 * n + 1; i++) if(!vs[i]) TPS(i);
//    cout << "here\n";
    memset(vs, 0, sizeof vs);
    for(int i = id; i ; i--) {
        int x = stk[i];
//        cout << "prpb " << x  << '\n';
        if(vs[x]) continue;
        cycle = samStal = 0;
        LL ml = DFS(x);
//        cout << x << ' ' << cycle << ' ' << samStal << '\n';
        if(samStal == 0) {
            if(cycle) ml = 2;
        }
        res = (res * ml) % MOD;
    }
    cout << res << "\n";
}


#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdlib>
#include <limits>
#include <iostream>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <random>
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;

#define gc getchar unlocked
#ifndef ONLINE JUDGE
#define gc getchar
#endif // ONLINE JUDGE

#define pc putchar_unlocked
#ifndef ONLINE JUDGE
#define pc putchar
#endif // ONLINE JUDGE

#define fRead           freopen("input.txt","r",stdin)
#define fWrite          freopen("output.txt","w",stdout)

#define eps             1e-9
#define inf             0x3f3f3f3f
#define INF             2e18
#define LL              long long
#define ULL             unsigned long long
#define PI              acos(-1.0)
#define pb              push_back
#define mk              make_pair
#define pii             pair<int,int>
#define pLL             pair<LL,LL>
#define ff              first
#define ss              second
#define all(a)          a.begin(),a.end()
#define rall(a)         a.rbegin(),a.rend()
#define SQR(a)          ((a)*(a))
#define Unique(a)       sort(all(a)),a.erase(unique(all(a)),a.end())
#define min3(a,b,c)     min(a,min(b,c))
#define max3(a,b,c)     max(a,max(b,c))
#define min4(a,b,c,d)   min(min(a,b),min(c,d))
#define max4(a,b,c,d)   max(max(a,b),max(c,d))
#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))
#define Iterator(a)     __typeof__(a.begin())
#define rIterator(a)    __typeof__(a.rbegin())
#define FOR(a,it)       for(Iterator(a) it = a.begin();it != a.end(); it++)
#define rFOR(a,it)      for(rIterator(a) it = a.rbegin();it != a.rend(); it++)
#define FastRead        ios_base::sync_with_stdio(0);cin.tie(0)
#define CasePrint       pc('C'); pc('a'); pc('s'); pc('e'); pc(' '); write(qq++,false); pc(':'); pc(' ')
#define vi              vector <int>
#define vL              vector <LL>
#define For(I,A,B)      for(int I = (A); I  < (B); ++I)
#define rFor(I,A,B)     for(int I = (A); I >= (B); --I)
#define Rep(I,N)        For(I,0,N)
#define REP(I,N)        For(I, 1, N + 1)
#define gti             int, vi, greater<int>
#define gtL             LL, vL, greater<LL>
#define Found(a, b)     a.find(b) != a.end()
#define y0              y00

const int MOD = 1e9 + 7;
int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//template <typename T> using orderset = tree <T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; // find_by_order, order_of_key
template <typename T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }
template <typename T> inline T GCD (T a,T b ) {a = abs(a);b = abs(b); if(a < b) swap(a, b); while ( b ) { a = a % b; swap ( a, b ); } return a;}
template <typename T> inline T EGCD(T a,T b,T &x,T &y){if(a == 0) {x = 0;y = 1;return b;}T x1, y1;T d = EGCD(b % a, a, x1, y1);x = y1 - (b / a) * x1;y = x1;return d;}
template <typename T> inline T LCM(T x,T y){T tp = GCD(x,y);if( (x / tp) * 1. * y > 9e18) return 9e18;return (x / tp) * y;}
template <typename T> inline T BigMod(T A,T B,T M = MOD){T ret = 1;while(B){if(B & 1) ret = (ret * A) % M;A = (A * A) % M;B = B >> 1;}return ret;}
template <typename T> inline T InvMod (T A,T M = MOD){return BigMod(A,M-2,M);}
template <typename T> void Compress(T * in, int n){vector <T> vv;for(int i = 0; i < n; i++) vv.pb(in[i]);Unique(vv);for(int i = 0; i < n; i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
//template <typename T> void Compress(vector <T> &in){vector <T> vv;for(T x : in) vv.pb(x);Unique(vv);for(int i = 0; i < in.size(); i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
/*---------------------------fast I/O------------------------------------*/
#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
template <typename T> T scani(T &n){n = 0;bool negative = false;char c = gc();while( c < '0' || c > '9'){if(c == '-') negative = true;c = gc();}while(c >= '0' && c <= '9'){n = n*10 + c-48;c = gc();}if(negative) n = ~(n-1);return n;}
template <typename T> void write(T n,int type = true){if(n<0) {pc('-');n = -n;}if(!n) {pc('0');if(type==32) pc(' '); else if(type) pc('\n'); return;}char buff[22];int len = 0;while(n) buff[len++] = n%10+48,n/=10;for(int i=len-1;i>=0;i--) pc(buff[i]);if(type==32) pc(' '); else if(type) pc('\n');}
int scans(char *a){int i=0;char c = 0;while(c < 33) c = gc();while(c > 33){a[i++] = c;c = gc();}a[i] = 0;return i;}
/*********************************************** End of template *********************************************/
#define Sieve

#ifdef Sieve
const int pSz = 2000006;
bool np[pSz + 10]; vi prime; int prime_size;void sieve(){np[0] = np[1] = 1;prime.pb(2);for(LL i = 4; i <= pSz; i+=2) np[i] = 1;for(LL i = 3; i <= pSz; i+=2){if(!np[i]){prime.pb(i);for(LL j = i * i; j <= pSz; j += (i << 1)) np[j] = 1;}}prime_size = prime.size();}
#endif

#ifdef Combi
const int nSz = 2000006;
LL F[nSz + 1], tMod = MOD;
void Factorial(){ F[0] = 1; for(int i = 1; i <= nSz; i++) F[i] = (F[i - 1] * i) % tMod; }
inline LL nCr(int n, int r) { return (F[n] * InvMod((F[n - r] * F[r]) % tMod, tMod)) % tMod; }
#endif

#ifdef Z_Algo
void zAlgo(char *s, int *z){
    int L, R, sz; sz = strlen(s); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(string &s, int *z){
    int L, R, sz; sz = s.size(); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(int *s, int *z, int n){
    int L, R, sz; sz = n; z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}
#endif // Z_Algo

/********************************************* define Template *************************************************/

template <typename T> inline T SqrDis(T x1, T y1, T x2, T y2){return SQR(x1 - x2) + SQR(y1 - y2);}
template <typename T> inline T Area2(T Ax, T Ay, T Bx, T By, T Cx, T Cy){T ret = Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By);
    if(ret < 0) return ret = -ret;
    return ret;
}
/**************************************************** GEO ******************************************************/
const int N = 400005; /** need to update this **/
const int M = 44444;
const ULL hs = 3797;
/** use data types carefully try to take 'long long' **/

vector <int> G[N];
int cl, ase, dd;
LL low, hi, md, inp[N], sm, ff, n;
bool vis[N];

void DFS(int x, int F)
{
    vis[x] = 1;
    ase++;
    for(int y : G[x]){
        if(y == x) dd = 1;
        if(y == F) continue;
        if(vis[y]) cl=1;
        if(!vis[y]) DFS(y,x);
    }
}
int main()
{
    cin >> n;
    vi tk;
    for(int i = 0; i < n; i++){
        int x, y;
        cin >> x >> y;
        tk.pb(x);
        G[y].pb(x);
        G[x].pb(y);
    }
    vector < pii > tk2;
    for(int i = 0; i < n; i++) tk2.pb(mk(G[tk[i]].size(),tk[i]));

    sort(all(tk2));
    reverse(all(tk2));
    LL ans = 1;
    for(auto y : tk2) {
        if(!vis[y.ss]) {
            dd = cl = ase = 0;
            DFS(y.ss, -1);
            if(dd) ans *= 1;
            else if(cl) ans *= 2;
            else ans *= ase;
            ans %= MOD;
        }
    }
    cout << ans << endl;
    return 0;
}


#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdlib>
#include <limits>
#include <iostream>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <random>
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;

#define gc getchar unlocked
#ifndef ONLINE JUDGE
#define gc getchar
#endif // ONLINE JUDGE

#define pc putchar_unlocked
#ifndef ONLINE JUDGE
#define pc putchar
#endif // ONLINE JUDGE

#define fRead           freopen("input.txt","r",stdin)
#define fWrite          freopen("output.txt","w",stdout)

#define eps             1e-9
#define inf             0x3f3f3f3f
#define INF             2e18
#define LL              long long
#define ULL             unsigned long long
#define PI              acos(-1.0)
#define pb              push_back
#define mk              make_pair
#define pii             pair<int,int>
#define pLL             pair<LL,LL>
#define ff              first
#define ss              second
#define all(a)          a.begin(),a.end()
#define rall(a)         a.rbegin(),a.rend()
#define SQR(a)          ((a)*(a))
#define Unique(a)       sort(all(a)),a.erase(unique(all(a)),a.end())
#define min3(a,b,c)     min(a,min(b,c))
#define max3(a,b,c)     max(a,max(b,c))
#define min4(a,b,c,d)   min(min(a,b),min(c,d))
#define max4(a,b,c,d)   max(max(a,b),max(c,d))
#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))
#define Iterator(a)     __typeof__(a.begin())
#define rIterator(a)    __typeof__(a.rbegin())
#define FOR(a,it)       for(Iterator(a) it = a.begin();it != a.end(); it++)
#define rFOR(a,it)      for(rIterator(a) it = a.rbegin();it != a.rend(); it++)
#define FastRead        ios_base::sync_with_stdio(0);cin.tie(0)
#define CasePrint       pc('C'); pc('a'); pc('s'); pc('e'); pc(' '); write(qq++,false); pc(':'); pc(' ')
#define vi              vector <int>
#define vL              vector <LL>
#define For(I,A,B)      for(int I = (A); I  < (B); ++I)
#define rFor(I,A,B)     for(int I = (A); I >= (B); --I)
#define Rep(I,N)        For(I,0,N)
#define REP(I,N)        For(I, 1, N + 1)
#define gti             int, vi, greater<int>
#define gtL             LL, vL, greater<LL>
#define Found(a, b)     a.find(b) != a.end()
#define y0              y00

const int MOD = 1e9 + 7;
int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//template <typename T> using orderset = tree <T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; // find_by_order, order_of_key
template <typename T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }
template <typename T> inline T GCD (T a,T b ) {a = abs(a);b = abs(b); if(a < b) swap(a, b); while ( b ) { a = a % b; swap ( a, b ); } return a;}
template <typename T> inline T EGCD(T a,T b,T &x,T &y){if(a == 0) {x = 0;y = 1;return b;}T x1, y1;T d = EGCD(b % a, a, x1, y1);x = y1 - (b / a) * x1;y = x1;return d;}
template <typename T> inline T LCM(T x,T y){T tp = GCD(x,y);if( (x / tp) * 1. * y > 9e18) return 9e18;return (x / tp) * y;}
template <typename T> inline T BigMod(T A,T B,T M = MOD){T ret = 1;while(B){if(B & 1) ret = (ret * A) % M;A = (A * A) % M;B = B >> 1;}return ret;}
template <typename T> inline T InvMod (T A,T M = MOD){return BigMod(A,M-2,M);}
template <typename T> void Compress(T * in, int n){vector <T> vv;for(int i = 0; i < n; i++) vv.pb(in[i]);Unique(vv);for(int i = 0; i < n; i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
//template <typename T> void Compress(vector <T> &in){vector <T> vv;for(T x : in) vv.pb(x);Unique(vv);for(int i = 0; i < in.size(); i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
/*---------------------------fast I/O------------------------------------*/
#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
template <typename T> T scani(T &n){n = 0;bool negative = false;char c = gc();while( c < '0' || c > '9'){if(c == '-') negative = true;c = gc();}while(c >= '0' && c <= '9'){n = n*10 + c-48;c = gc();}if(negative) n = ~(n-1);return n;}
template <typename T> void write(T n,int type = true){if(n<0) {pc('-');n = -n;}if(!n) {pc('0');if(type==32) pc(' '); else if(type) pc('\n'); return;}char buff[22];int len = 0;while(n) buff[len++] = n%10+48,n/=10;for(int i=len-1;i>=0;i--) pc(buff[i]);if(type==32) pc(' '); else if(type) pc('\n');}
int scans(char *a){int i=0;char c = 0;while(c < 33) c = gc();while(c > 33){a[i++] = c;c = gc();}a[i] = 0;return i;}
/*********************************************** End of template *********************************************/
#define Sieve

#ifdef Sieve
const int pSz = 2000006;
bool np[pSz + 10]; vi prime; int prime_size;void sieve(){np[0] = np[1] = 1;prime.pb(2);for(LL i = 4; i <= pSz; i+=2) np[i] = 1;for(LL i = 3; i <= pSz; i+=2){if(!np[i]){prime.pb(i);for(LL j = i * i; j <= pSz; j += (i << 1)) np[j] = 1;}}prime_size = prime.size();}
#endif

#ifdef Combi
const int nSz = 2000006;
LL F[nSz + 1], tMod = MOD;
void Factorial(){ F[0] = 1; for(int i = 1; i <= nSz; i++) F[i] = (F[i - 1] * i) % tMod; }
inline LL nCr(int n, int r) { return (F[n] * InvMod((F[n - r] * F[r]) % tMod, tMod)) % tMod; }
#endif

#ifdef Z_Algo
void zAlgo(char *s, int *z){
    int L, R, sz; sz = strlen(s); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(string &s, int *z){
    int L, R, sz; sz = s.size(); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(int *s, int *z, int n){
    int L, R, sz; sz = n; z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}
#endif // Z_Algo

/********************************************* define Template *************************************************/

template <typename T> inline T SqrDis(T x1, T y1, T x2, T y2){return SQR(x1 - x2) + SQR(y1 - y2);}
template <typename T> inline T Area2(T Ax, T Ay, T Bx, T By, T Cx, T Cy){T ret = Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By);
    if(ret < 0) return ret = -ret;
    return ret;
}
/**************************************************** GEO ******************************************************/
const int N = 400005; /** need to update this **/
const int M = 44444;
const ULL hs = 3797;
/** use data types carefully try to take 'long long' **/

int pr[N], n, in[N], state[N], sz[N];

int find(int x) {
    if(x == pr[x]) return x;
    return pr[x] = find(pr[x]);
}

int main()
{
    scani(n);
    For(i, 1, n * 2 + 1) pr[i] = i, sz[i] = 1;
    For(i, 1, n + 1) {
        int x, y; scani2(x, y);
        if(x == y) {
            state[find(x)] = 2;
            continue;
        }
        x = find(x);
        y = find(y);
        if(x == y) state[x] = 1;
        else {
            pr[x] = y;
            sz[y] += sz[x];
            state[y] |= state[x];
        }
    }
    LL res = 1;
    For(i, 1, 1 + 2 * n) if(find(i) == i) {
        if(state[i] == 0) res = res * sz[i] % MOD;
        if(state[i] == 1) res = res * 2 % MOD;
    }
    write(res);
    return 0;
}


#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <cstdlib>
#include <limits>
#include <iostream>
#include <sstream>
#include <unordered_set>
#include <unordered_map>
#include <random>
#include <bits/stdc++.h>
//#include <ext/pb_ds/assoc_container.hpp>
//using namespace __gnu_pbds;
using namespace std;

#define gc getchar unlocked
#ifndef ONLINE JUDGE
#define gc getchar
#endif // ONLINE JUDGE

#define pc putchar_unlocked
#ifndef ONLINE JUDGE
#define pc putchar
#endif // ONLINE JUDGE

#define fRead           freopen("input.txt","r",stdin)
#define fWrite          freopen("output.txt","w",stdout)

#define eps             1e-9
#define inf             0x3f3f3f3f
#define INF             2e18
#define LL              long long
#define ULL             unsigned long long
#define PI              acos(-1.0)
#define pb              push_back
#define mk              make_pair
#define pii             pair<int,int>
#define pLL             pair<LL,LL>
#define ff              first
#define ss              second
#define all(a)          a.begin(),a.end()
#define rall(a)         a.rbegin(),a.rend()
#define SQR(a)          ((a)*(a))
#define Unique(a)       sort(all(a)),a.erase(unique(all(a)),a.end())
#define min3(a,b,c)     min(a,min(b,c))
#define max3(a,b,c)     max(a,max(b,c))
#define min4(a,b,c,d)   min(min(a,b),min(c,d))
#define max4(a,b,c,d)   max(max(a,b),max(c,d))
#define max5(a,b,c,d,e) max(max3(a,b,c),max(d,e))
#define min5(a,b,c,d,e) min(min3(a,b,c),min(d,e))
#define Iterator(a)     __typeof__(a.begin())
#define rIterator(a)    __typeof__(a.rbegin())
#define FOR(a,it)       for(Iterator(a) it = a.begin();it != a.end(); it++)
#define rFOR(a,it)      for(rIterator(a) it = a.rbegin();it != a.rend(); it++)
#define FastRead        ios_base::sync_with_stdio(0);cin.tie(0)
#define CasePrint       pc('C'); pc('a'); pc('s'); pc('e'); pc(' '); write(qq++,false); pc(':'); pc(' ')
#define vi              vector <int>
#define vL              vector <LL>
#define For(I,A,B)      for(int I = (A); I  < (B); ++I)
#define rFor(I,A,B)     for(int I = (A); I >= (B); --I)
#define Rep(I,N)        For(I,0,N)
#define REP(I,N)        For(I, 1, N + 1)
#define gti             int, vi, greater<int>
#define gtL             LL, vL, greater<LL>
#define Found(a, b)     a.find(b) != a.end()
#define y0              y00

const int MOD = 1e9 + 7;
int fx[] = {-1,+0,+1,+0,+1,+1,-1,-1,+0};
int fy[] = {+0,-1,+0,+1,+1,-1,+1,-1,+0};
int day[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//template <typename T> using orderset = tree <T, null_type, less<T>, rb_tree_tag,tree_order_statistics_node_update>; // find_by_order, order_of_key
template <typename T> inline bool isLeap(T y) {return (y % 400 == 0) || (y % 100 ? y % 4 == 0 : false); }
template <typename T> inline T GCD (T a,T b ) {a = abs(a);b = abs(b); if(a < b) swap(a, b); while ( b ) { a = a % b; swap ( a, b ); } return a;}
template <typename T> inline T EGCD(T a,T b,T &x,T &y){if(a == 0) {x = 0;y = 1;return b;}T x1, y1;T d = EGCD(b % a, a, x1, y1);x = y1 - (b / a) * x1;y = x1;return d;}
template <typename T> inline T LCM(T x,T y){T tp = GCD(x,y);if( (x / tp) * 1. * y > 9e18) return 9e18;return (x / tp) * y;}
template <typename T> inline T BigMod(T A,T B,T M = MOD){T ret = 1;while(B){if(B & 1) ret = (ret * A) % M;A = (A * A) % M;B = B >> 1;}return ret;}
template <typename T> inline T InvMod (T A,T M = MOD){return BigMod(A,M-2,M);}
template <typename T> void Compress(T * in, int n){vector <T> vv;for(int i = 0; i < n; i++) vv.pb(in[i]);Unique(vv);for(int i = 0; i < n; i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
//template <typename T> void Compress(vector <T> &in){vector <T> vv;for(T x : in) vv.pb(x);Unique(vv);for(int i = 0; i < in.size(); i++) in[i] = lower_bound(all(vv), in[i]) - vv.begin();}
/*---------------------------fast I/O------------------------------------*/
#define scani2(a,b) scani(a) , scani(b)
#define scani3(a,b,c) scani(a), scani(b), scani(c)
#define scani4(a,b,c,d) scani(a), scani(b), scani(c), scani(d)
#define scani5(a,b,c,d,e) scani(a), scani(b), scani(c), scani(d) , scani(e)
template <typename T> T scani(T &n){n = 0;bool negative = false;char c = gc();while( c < '0' || c > '9'){if(c == '-') negative = true;c = gc();}while(c >= '0' && c <= '9'){n = n*10 + c-48;c = gc();}if(negative) n = ~(n-1);return n;}
template <typename T> void write(T n,int type = true){if(n<0) {pc('-');n = -n;}if(!n) {pc('0');if(type==32) pc(' '); else if(type) pc('\n'); return;}char buff[22];int len = 0;while(n) buff[len++] = n%10+48,n/=10;for(int i=len-1;i>=0;i--) pc(buff[i]);if(type==32) pc(' '); else if(type) pc('\n');}
int scans(char *a){int i=0;char c = 0;while(c < 33) c = gc();while(c > 33){a[i++] = c;c = gc();}a[i] = 0;return i;}
/*********************************************** End of template *********************************************/
#define Sieve

#ifdef Sieve
const int pSz = 2000006;
bool np[pSz + 10]; vi prime; int prime_size;void sieve(){np[0] = np[1] = 1;prime.pb(2);for(LL i = 4; i <= pSz; i+=2) np[i] = 1;for(LL i = 3; i <= pSz; i+=2){if(!np[i]){prime.pb(i);for(LL j = i * i; j <= pSz; j += (i << 1)) np[j] = 1;}}prime_size = prime.size();}
#endif

#ifdef Combi
const int nSz = 2000006;
LL F[nSz + 1], tMod = MOD;
void Factorial(){ F[0] = 1; for(int i = 1; i <= nSz; i++) F[i] = (F[i - 1] * i) % tMod; }
inline LL nCr(int n, int r) { return (F[n] * InvMod((F[n - r] * F[r]) % tMod, tMod)) % tMod; }
#endif

#ifdef Z_Algo
void zAlgo(char *s, int *z){
    int L, R, sz; sz = strlen(s); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(string &s, int *z){
    int L, R, sz; sz = s.size(); z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}void zAlgo(int *s, int *z, int n){
    int L, R, sz; sz = n; z[0] = L = R = 0;
    For(i, 1, sz) { z[i] = 0; if(i <= R) z[i] = min(z[i - L], R - i + 1); while(i + z[i] < sz && s[i + z[i]] == s[z[i]]) z[i]++; if(i + z[i] - 1 > R) L = i, R = i + z[i] - 1; }
}
#endif // Z_Algo

/********************************************* define Template *************************************************/

template <typename T> inline T SqrDis(T x1, T y1, T x2, T y2){return SQR(x1 - x2) + SQR(y1 - y2);}
template <typename T> inline T Area2(T Ax, T Ay, T Bx, T By, T Cx, T Cy){T ret = Ax * (By - Cy) + Bx * (Cy - Ay) + Cx * (Ay - By);
    if(ret < 0) return ret = -ret;
    return ret;
}
/**************************************************** GEO ******************************************************/
const int N = 400005; /** need to update this **/
const int M = 44444;
const ULL hs = 3797;
/** use data types carefully try to take 'long long' **/

vector <int> G[N];
int cl, ase, dd;
LL low, hi, md, inp[N], sm, ff, n;
bool vis[N];

void DFS(int x, int F)
{
    vis[x] = 1;
    ase++;
    for(int y : G[x]){
        if(y == x) dd = 1;
        if(y == F) continue;
        if(vis[y]) cl=1;
        if(!vis[y]) DFS(y,x);

    }
}
int main()
{
    cin >> n;
    vector<int> tk;
    for(int i = 0; i < n; i++)
    {
        int x, y;
        cin >> x >> y;
        tk.pb(x);
        G[y].pb(x);
        G[x].pb(y);
    }
    vector<pair<int,int> > tk2;
    for(int i = 0; i < n; i++)
    {
        tk2.pb(make_pair(G[tk[i]].size(),tk[i]));
    }
    sort(tk2.begin(),tk2.end());
    reverse(tk2.begin(),tk2.end());
    LL ans = 1;
    LL mod = 1000000007LL;
    for(auto y : tk2) {
        if(!vis[y.ss]) {
            dd = cl = ase = 0;
            DFS(y.ss,-1);
//            cerr<<y.ss<<" "<<ase<<endl;
            if(dd) ans *= 1;
            else if(cl) ans *= 2;
            else ans *= ase;
            ans %= mod;
        }
    }
    cout << ans << endl;
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i, a, b) for(int i=a; i<b; i++)
#define ffi For(i, 0, N)
#define ffj For(j, 0, M)
#define ffa ffi ffj
#define s <<" "<<
#define w cout
#define e endl
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define int ll
//500,000,000 operations
//Global Variables
const int MAXN = 200000, MOD = 1000000007;
int N, ce, cv, ans = 1;
bool vis[MAXN], loop[MAXN], lo;
vector<int> adj[MAXN];

void go(int at) {
	if (vis[at]) return;
	vis[at] = true;
	cv ++;
	ce += adj[at].size();
	for (int i: adj[at]) {
		go(i);
		if (i == at) lo = true;
	}
}

main() {
	//ifstream cin ("test.in");
	ios_base::sync_with_stdio; cin.tie(0);
	cin >> N;
	ffi {
		int a, b; cin >> a >> b; a--; b--;
		if (a != b) loop[a] = true;
		adj[a].pb(b), adj[b].pb(a);
	}
	N *= 2;
	ffi if (!vis[i]) {
		ce = cv = 0, lo = false;
		go(i);
		ce /= 2;
		//if (cv != 1) w<< i s cv s ce s lo<<e;
		if (lo) {}
		else if (ce == cv && !lo) ans *= 2;
		else if (ce = cv - 1) ans *= cv;
		else if (cv == 1) {}
		else assert(false);
		ans %= MOD;
	}
	w<< ans<<e;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i, a, b) for(int i=a; i<b; i++)
#define ffi For(i, 0, N)
#define ffj For(j, 0, M)
#define ffa ffi ffj
#define s <<" "<<
#define w cout
#define e endl
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define int ll
//500,000,000 operations
//Global Variables
const int MAXN = 200000, MOD = 1000000007;
int N, ce, cv, ans = 1;
bool vis[MAXN], lo;
vector<int> adj[MAXN];

void go(int at) {
	if (vis[at]) return;
	vis[at] = true;
	cv ++;
	ce += adj[at].size();
	for (int i: adj[at]) {
		go(i);
		if (i == at) lo = true;
	}
}

main() {
	//ifstream cin ("test.in");
	ios_base::sync_with_stdio; cin.tie(0);
	cin >> N;
	ffi {
		int a, b; cin >> a >> b; a--; b--;
		adj[a].pb(b), adj[b].pb(a);
	}
	N *= 2;
	ffi if (!vis[i]) {
		ce = cv = 0, lo = false;
		go(i);
		ce /= 2;
		//if (cv != 1) w<< i s cv s ce s lo<<e;
		if (lo) {}
		else if (ce == cv && !lo) ans *= 2;
		else if (ce = cv - 1) ans *= cv;
		else if (cv == 1) {}
		else assert(false);
		ans %= MOD;
	}
	w<< ans<<e;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i, a, b) for(int i=a; i<b; i++)
#define ffi For(i, 0, N)
#define ffj For(j, 0, M)
#define ffa ffi ffj
#define s <<" "<<
#define w cout
#define e endl
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define int ll
//500,000,000 operations
//Global Variables
const int MAXN = 100000, MOD = 1000000007;
int N, ce, cv, ans = 1;
bool vis[MAXN];
vector<int> adj[MAXN];

void go(int at) {
	if (vis[at]) return;
	vis[at] = true;
	cv ++;
	ce += adj[at].size();
	for (int i: adj[at]) go(i);
}

main() {
	//ifstream cin ("test.in");
	ios_base::sync_with_stdio; cin.tie(0);
	cin >> N;
	ffi {
		int a, b; cin >> a >> b; a--; b--;
		if (a != b) adj[a].pb(b), adj[b].pb(a);
	}
	ffi if (!vis[i]) {
		ce = cv = 0;
		go(i);
		//w<< cv s ce<<e;
		ce /= 2;
		if (ce == cv) ans *= 2;
		else if (ce = cv - 1) ans *= cv;
		else if (cv == 1) {}
		else assert(false);
	}
	w<< ans<<e;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i, a, b) for(int i=a; i<b; i++)
#define ffi For(i, 0, N)
#define ffj For(j, 0, M)
#define ffa ffi ffj
#define s <<" "<<
#define w cout
#define e endl
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define int ll
//500,000,000 operations
//Global Variables
const int MAXN = 200000, MOD = 1000000007;
int N, ce, cv, ans = 1;
bool vis[MAXN];
vector<int> adj[MAXN];

void go(int at) {
	if (vis[at]) return;
	vis[at] = true;
	cv ++;
	ce += adj[at].size();
	for (int i: adj[at]) go(i);
}

main() {
	//ifstream cin ("test.in");
	ios_base::sync_with_stdio; cin.tie(0);
	cin >> N;
	ffi {
		int a, b; cin >> a >> b; a--; b--;
		if (a != b) adj[a].pb(b), adj[b].pb(a);
	}
	ffi if (!vis[i]) {
		ce = cv = 0;
		go(i);
		//w<< cv s ce<<e;
		ce /= 2;
		if (ce == cv) ans *= 2;
		else if (ce = cv - 1) ans *= cv;
		else if (cv == 1) {}
		else assert(false);
		ans %= MOD;
	}
	w<< ans<<e;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define For(i, a, b) for(int i=a; i<b; i++)
#define ffi For(i, 0, N)
#define ffj For(j, 0, M)
#define ffa ffi ffj
#define s <<" "<<
#define w cout
#define e endl
#define pb push_back
#define mp make_pair
#define a first
#define b second
#define int ll
//500,000,000 operations
//Global Variables
const int MAXN = 100000, MOD = 1000000007;
int N, ce, cv, ans = 1;
bool vis[MAXN];
vector<int> adj[MAXN];

void go(int at) {
	if (vis[at]) return;
	vis[at] = true;
	cv ++;
	ce += adj[at].size();
	for (int i: adj[at]) go(i);
}

main() {
	//ifstream cin ("test.in");
	ios_base::sync_with_stdio; cin.tie(0);
	cin >> N;
	ffi {
		int a, b; cin >> a >> b; a--; b--;
		if (a != b) adj[a].pb(b), adj[b].pb(a);
	}
	ffi if (!vis[i]) {
		ce = cv = 0;
		go(i);
		//w<< cv s ce<<e;
		ce /= 2;
		if (ce == cv) ans *= 2;
		else if (ce = cv - 1) ans *= cv;
		else if (cv == 1) {}
		else assert(false);
		ans %= MOD;
	}
	w<< ans<<e;
}


#include <string>
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<functional>
#include<list>
#include<deque>
#include<bitset>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<cstring>
#include<sstream>
#include<complex>
#include<iomanip>
#include<numeric>
#include<cassert>
#define X first
#define Y second
#define pb push_back
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
#define repe(X,Y) for ((X) = 0;(X) < (Y);++(X))
#define peat(X,Y) for (;(X) < (Y);++(X))
#define all(X) (X).begin(),(X).end()
#define rall(X) (X).rbegin(),(X).rend()
#define eb emplace_back
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define Endl endl

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<class T> using vv=vector<vector<T>>;
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"{"; rep(i,t.size()) {os<<t[i]<<",";} os<<"}"<<endl; return os;}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}
#define out(args...){vector<string> a_r_g_s=s_p_l_i_t(#args, ','); e_r_r(a_r_g_s.begin(), args); }
vector<string> s_p_l_i_t(const string &s, char c){vector<string> v;int d=0,f=0;string t;for(char c:s){if(!d&&c==',')v.pb(t),t="";else t+=c;if(c=='\"'||c=='\'')f^=1;if(!f&&c=='(')++d;if(!f&&c==')')--d;}v.pb(t);return move(v);}
void e_r_r(vector<string>::iterator it) {}
template<typename T, typename... Args> void e_r_r(vector<string>::iterator it, T a, Args... args){ if(*it==" 1"||*it=="1") cerr<<endl; else cerr << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << ", "; e_r_r(++it, args...);}
const ll MOD=1e9+7;
typedef vv<int> Graph;
struct Scc{
  stack<int> S;
  vector<int> inS,low,num;
  int time;
public:
  Graph dag;
  vector<int> inv;
  vv<int> scc;
  void visit(const Graph &g, int v){
    low[v] = num[v] = ++time;
    S.push(v); inS[v]=1;
    for(const int  &w:g[v]) {
      if(!num[w]){
	visit(g,w);
	low[v]=min(low[v],low[w]);
      }else if(inS[w])
	low[v]=min(low[v],num[w]);
    }
    if(low[v]==num[v]){
      scc.push_back(vector<int>());
      while(1){
	int w = S.top(); S.pop(); inS[w]=0;
	scc.back().push_back(w);
	if (v==w) break;
      }
    }
  }
  Scc(const Graph &g) {
    const int n = g.size();
    num.resize(n); low.resize(n); inS.resize(n);
    rep(u,n) if(!num[u])
      visit(g,u);
    reverse(all(scc));

    inv.resize(n); dag.resize(n);
    rep(i,scc.size()) rep(j,scc[i].size())
      inv[scc[i][j]]=i;
    rep(i,scc.size()) rep(j,scc[i].size())
      for(auto e:g[scc[i][j]])
	if(inv[e] != i)
	  dag[i].pb(inv[e]);
  }
};
ll modpow(ll r,ll n,ll m=MOD){
  ll re=1,d=r%m;
  if(n<0)(n%=m-1)+=m-1;
  for(;n;n/=2){
    if(n&1)(re*=d)%=m;
    (d*=d)%=m;
  }
  return re;
}
template <int mod=MOD> struct modInt{
  int v;
  modInt(int v=0):v(v){}
  modInt operator+(const modInt &n){return v+n.v<mod ? v+n.v : v+n.v-mod;}
  modInt operator-(const modInt &n){return v-n.v<0 ? v-n.v+mod : v-n.v;}
  modInt operator*(const modInt &n){return ll(v)*n.v%mod;}
  modInt operator/(const modInt &n){return ll(v)*modpow(n.v%mod,-1,mod)%mod;}
  modInt operator+(const ll &n){return v+n<mod ? v+n : v+n-mod;}
  modInt operator-(const ll &n){return v-n<0 ? v-n+mod : v-n;}
  modInt operator*(const ll &n){return ll(v)*(n%mod)%mod;}
  modInt operator/(const ll &n){return ll(v)*modpow(n%mod,-1,mod)%mod;}
  modInt& operator+=(const modInt &n){v+=n.v; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const modInt &n){v-=n.v; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const modInt &n){v=ll(v)*n.v%mod; return *this;}
  modInt& operator/=(const modInt &n){v=ll(v)*modpow(n.v,-1,mod)%mod; return *this;}
  modInt& operator+=(const ll &n){v+=n; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const ll &n){v-=n; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const ll &n){v=ll(v)*n%mod; return *this;}
  modInt& operator/=(const ll &n){v=ll(v)*modpow(n,-1,mod)%mod; return *this;}
};
template<int mod> ostream& operator<<(ostream &os,const modInt<mod> &n){return os<<n.v;};
template<int mod> modInt<mod> operator+(const ll &n,const modInt<mod> &m){return m.v+n<mod ? m.v+n : m.v+n-mod;}
template<int mod> modInt<mod> operator-(const ll &n,const modInt<mod> &m){return n-m.v<0 ? n-m.v+mod : n-m.v;}
template<int mod> modInt<mod> operator*(const ll &n,const modInt<mod> &m){return ll(m.v)*(n%mod)%mod;}
template<int mod> modInt<mod> operator/(const ll &n,const modInt<mod> &m){return ll(m.v)*modpow(n%mod,-1,mod)%mod;}
typedef modInt<MOD> mint;
template <int mod> modInt<mod> modpow(modInt<mod> r,ll n){ modInt<mod> re(1); if(n<0)(n%=mod-1)+=mod-1; for(;n;n/=2){if(n&1) re*=r; r*=r;} return re;}
vector<mint> fact,finv,inv;
mint comb(ll n,ll r){ if(n<r||r<0)return 0; return fact[n]*finv[n-r]*finv[r];}
class Doralion{
  void Modinvs(vector<mint> &re,int n){ re.resize(n+1); re[1]=1; for(int i=2;i<=n;++i)re[i]=re[MOD%i]*(MOD-MOD/i);}
  void Facts(vector<mint> &re,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*(i+1);}
  void Factinvs(vector<mint> &re,const vector<mint> &inv,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*inv[i+1];}
public:
  Doralion(int n){ Modinvs(inv,n); Facts(fact,n); Factinvs(finv,inv,n);}
} doralion(212345);
struct UF{
  vector<int> data;
  UF(int size):data(size,-1){}
  bool unite(int x,int y){
    x=root(x); y=root(y);
    if(x!=y){
      if(data[y]<data[x]) swap(x,y);
      data[x]+=data[y]; data[y]=x;
    }
    return x!=y;
  }
  bool findSet(int x,int y){return root(x)==root(y);}
  int root(int x){return data[x]<0?x:data[x]=root(data[x]);}
  int size(int x) {return -data[root(x)];}
};

int main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);
	int n;
	cin>>n;
	vv<int> g(2*n);
	UF uf(2*n);
	rep(i,n){
		int x,y;
		cin>>x>>y; --x; --y;
		uf.unite(x,y);
		if(x!=y)
			g[y].pb(x);
	}
	vector<int> es(2*n);
	rep(i,2*n) es[uf.root(i)]+=g[i].size();
	mint re=1;
	rep(i,2*n)if(uf.root(i)==i && uf.size(i)>1){
		if(es[i]==uf.size(i)){
			re*=2;
		}else if(es[i]+1==uf.size(i)){
			re*=uf.size(i);
		}
	}
	cout<<re<<endl;
  return 0;
}


#include <string>
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<functional>
#include<list>
#include<deque>
#include<bitset>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<cstring>
#include<sstream>
#include<complex>
#include<iomanip>
#include<numeric>
#include<cassert>
#define X first
#define Y second
#define pb push_back
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
#define repe(X,Y) for ((X) = 0;(X) < (Y);++(X))
#define peat(X,Y) for (;(X) < (Y);++(X))
#define all(X) (X).begin(),(X).end()
#define rall(X) (X).rbegin(),(X).rend()
#define eb emplace_back
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define Endl endl

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<class T> using vv=vector<vector<T>>;
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"{"; rep(i,t.size()) {os<<t[i]<<",";} os<<"}"<<endl; return os;}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}
#define out(args...){vector<string> a_r_g_s=s_p_l_i_t(#args, ','); e_r_r(a_r_g_s.begin(), args); }
vector<string> s_p_l_i_t(const string &s, char c){vector<string> v;int d=0,f=0;string t;for(char c:s){if(!d&&c==',')v.pb(t),t="";else t+=c;if(c=='\"'||c=='\'')f^=1;if(!f&&c=='(')++d;if(!f&&c==')')--d;}v.pb(t);return move(v);}
void e_r_r(vector<string>::iterator it) {}
template<typename T, typename... Args> void e_r_r(vector<string>::iterator it, T a, Args... args){ if(*it==" 1"||*it=="1") cerr<<endl; else cerr << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << ", "; e_r_r(++it, args...);}
const ll MOD=1e9+7;
typedef vv<int> Graph;
struct Scc{
  stack<int> S;
  vector<int> inS,low,num;
  int time=0;
public:
  Graph dag;
  vector<int> inv;
  vv<int> scc;
  void visit(const Graph &g, int v){
    low[v] = num[v] = ++time;
    S.push(v); inS[v]=1;
    for(const int  &w:g[v]){
      if(!num[w]){
				visit(g,w);
				low[v]=min(low[v],low[w]);
      }else if(inS[w]) low[v]=min(low[v],num[w]);
    }
    if(low[v]==num[v]){
      scc.eb();
      while(1){
				assert(S.size());
				int w = S.top(); S.pop(); inS[w]=0;
				scc.back().pb(w);
				if (v==w) break;
      }
    }
  }
  Scc(const Graph &g) {
    const int n = g.size();
    num.resize(n); low.resize(n); inS.resize(n);
    rep(u,n)if(!num[u]) visit(g,u);
    reverse(all(scc));

    inv.resize(n); dag.resize(n);
    rep(i,scc.size())rep(j,scc[i].size()) inv[scc[i][j]]=i;
    rep(i,scc.size())rep(j,scc[i].size())for(auto e:g[scc[i][j]])
			if(inv[e] != i)	dag[i].pb(inv[e]);
  }
};
ll modpow(ll r,ll n,ll m=MOD){
  ll re=1,d=r%m;
  if(n<0)(n%=m-1)+=m-1;
  for(;n;n/=2){
    if(n&1)(re*=d)%=m;
    (d*=d)%=m;
  }
  return re;
}
template <int mod=MOD> struct modInt{
  int v;
  modInt(int v=0):v(v){}
  modInt operator+(const modInt &n){return v+n.v<mod ? v+n.v : v+n.v-mod;}
  modInt operator-(const modInt &n){return v-n.v<0 ? v-n.v+mod : v-n.v;}
  modInt operator*(const modInt &n){return ll(v)*n.v%mod;}
  modInt operator/(const modInt &n){return ll(v)*modpow(n.v%mod,-1,mod)%mod;}
  modInt operator+(const ll &n){return v+n<mod ? v+n : v+n-mod;}
  modInt operator-(const ll &n){return v-n<0 ? v-n+mod : v-n;}
  modInt operator*(const ll &n){return ll(v)*(n%mod)%mod;}
  modInt operator/(const ll &n){return ll(v)*modpow(n%mod,-1,mod)%mod;}
  modInt& operator+=(const modInt &n){v+=n.v; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const modInt &n){v-=n.v; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const modInt &n){v=ll(v)*n.v%mod; return *this;}
  modInt& operator/=(const modInt &n){v=ll(v)*modpow(n.v,-1,mod)%mod; return *this;}
  modInt& operator+=(const ll &n){v+=n; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const ll &n){v-=n; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const ll &n){v=ll(v)*n%mod; return *this;}
  modInt& operator/=(const ll &n){v=ll(v)*modpow(n,-1,mod)%mod; return *this;}
};
template<int mod> ostream& operator<<(ostream &os,const modInt<mod> &n){return os<<n.v;};
template<int mod> modInt<mod> operator+(const ll &n,const modInt<mod> &m){return m.v+n<mod ? m.v+n : m.v+n-mod;}
template<int mod> modInt<mod> operator-(const ll &n,const modInt<mod> &m){return n-m.v<0 ? n-m.v+mod : n-m.v;}
template<int mod> modInt<mod> operator*(const ll &n,const modInt<mod> &m){return ll(m.v)*(n%mod)%mod;}
template<int mod> modInt<mod> operator/(const ll &n,const modInt<mod> &m){return ll(m.v)*modpow(n%mod,-1,mod)%mod;}
typedef modInt<MOD> mint;
template <int mod> modInt<mod> modpow(modInt<mod> r,ll n){ modInt<mod> re(1); if(n<0)(n%=mod-1)+=mod-1; for(;n;n/=2){if(n&1) re*=r; r*=r;} return re;}
vector<mint> fact,finv,inv;
mint comb(ll n,ll r){ if(n<r||r<0)return 0; return fact[n]*finv[n-r]*finv[r];}
class Doralion{
  void Modinvs(vector<mint> &re,int n){ re.resize(n+1); re[1]=1; for(int i=2;i<=n;++i)re[i]=re[MOD%i]*(MOD-MOD/i);}
  void Facts(vector<mint> &re,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*(i+1);}
  void Factinvs(vector<mint> &re,const vector<mint> &inv,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*inv[i+1];}
public:
  Doralion(int n){ Modinvs(inv,n); Facts(fact,n); Factinvs(finv,inv,n);}
} doralion(212345);

int main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);
	int n;
	cin>>n;
	vv<int> g(2*n);
	rep(i,n){
		int x,y;
		cin>>x>>y; --x; --y;
		if(x!=y)
			g[y].pb(x);
	}
	Scc h(g);
	vector<int> usd(2*n);
	vector<int> ind(2*n);
	rep(i,h.dag.size())for(int v:h.dag[i]) ++ind[v];
	function<int(int)> dfs=[&](int v){
		int re=1;
		for(int w:h.dag[v]) re+=dfs(w);
		return re;
	};
	mint re=1;
	rep(i,2*n){
		int id=h.inv[i];
		if(ind[id] || MX(usd[id],1)==0) continue;
		if(h.dag[id].size()==0 && h.scc[id].size()==1) continue;
		int sz=dfs(id);
		if(h.scc[id].size()>1){
			re*=2;
		}else{
			re*=sz;
		}
	}
	cout<<re<<endl;
  return 0;
}


#include <string>
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<functional>
#include<list>
#include<deque>
#include<bitset>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<cstring>
#include<sstream>
#include<complex>
#include<iomanip>
#include<numeric>
#include<cassert>
#define X first
#define Y second
#define pb push_back
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
#define repe(X,Y) for ((X) = 0;(X) < (Y);++(X))
#define peat(X,Y) for (;(X) < (Y);++(X))
#define all(X) (X).begin(),(X).end()
#define rall(X) (X).rbegin(),(X).rend()
#define eb emplace_back
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define Endl endl

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<class T> using vv=vector<vector<T>>;
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"{"; rep(i,t.size()) {os<<t[i]<<",";} os<<"}"<<endl; return os;}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}
#define out(args...){vector<string> a_r_g_s=s_p_l_i_t(#args, ','); e_r_r(a_r_g_s.begin(), args); }
vector<string> s_p_l_i_t(const string &s, char c){vector<string> v;int d=0,f=0;string t;for(char c:s){if(!d&&c==',')v.pb(t),t="";else t+=c;if(c=='\"'||c=='\'')f^=1;if(!f&&c=='(')++d;if(!f&&c==')')--d;}v.pb(t);return move(v);}
void e_r_r(vector<string>::iterator it) {}
template<typename T, typename... Args> void e_r_r(vector<string>::iterator it, T a, Args... args){ if(*it==" 1"||*it=="1") cerr<<endl; else cerr << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << ", "; e_r_r(++it, args...);}
const ll MOD=1e9+7;
typedef vv<int> Graph;
struct Scc{
  stack<int> S;
  vector<int> inS,low,num;
  int time;
public:
  Graph dag;
  vector<int> inv;
  vv<int> scc;
  void visit(const Graph &g, int v){
    low[v] = num[v] = ++time;
    S.push(v); inS[v]=1;
    for(const int  &w:g[v]) {
      if(!num[w]){
	visit(g,w);
	low[v]=min(low[v],low[w]);
      }else if(inS[w])
	low[v]=min(low[v],num[w]);
    }
    if(low[v]==num[v]){
      scc.push_back(vector<int>());
      while(1){
	int w = S.top(); S.pop(); inS[w]=0;
	scc.back().push_back(w);
	if (v==w) break;
      }
    }
  }
  Scc(const Graph &g) {
    const int n = g.size();
    num.resize(n); low.resize(n); inS.resize(n);
    rep(u,n) if(!num[u])
      visit(g,u);
    reverse(all(scc));

    inv.resize(n); dag.resize(n);
    rep(i,scc.size()) rep(j,scc[i].size())
      inv[scc[i][j]]=i;
    rep(i,scc.size()) rep(j,scc[i].size())
      for(auto e:g[scc[i][j]])
	if(inv[e] != i)
	  dag[i].pb(inv[e]);
  }
};
ll modpow(ll r,ll n,ll m=MOD){
  ll re=1,d=r%m;
  if(n<0)(n%=m-1)+=m-1;
  for(;n;n/=2){
    if(n&1)(re*=d)%=m;
    (d*=d)%=m;
  }
  return re;
}
template <int mod=MOD> struct modInt{
  int v;
  modInt(int v=0):v(v){}
  modInt operator+(const modInt &n){return v+n.v<mod ? v+n.v : v+n.v-mod;}
  modInt operator-(const modInt &n){return v-n.v<0 ? v-n.v+mod : v-n.v;}
  modInt operator*(const modInt &n){return ll(v)*n.v%mod;}
  modInt operator/(const modInt &n){return ll(v)*modpow(n.v%mod,-1,mod)%mod;}
  modInt operator+(const ll &n){return v+n<mod ? v+n : v+n-mod;}
  modInt operator-(const ll &n){return v-n<0 ? v-n+mod : v-n;}
  modInt operator*(const ll &n){return ll(v)*(n%mod)%mod;}
  modInt operator/(const ll &n){return ll(v)*modpow(n%mod,-1,mod)%mod;}
  modInt& operator+=(const modInt &n){v+=n.v; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const modInt &n){v-=n.v; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const modInt &n){v=ll(v)*n.v%mod; return *this;}
  modInt& operator/=(const modInt &n){v=ll(v)*modpow(n.v,-1,mod)%mod; return *this;}
  modInt& operator+=(const ll &n){v+=n; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const ll &n){v-=n; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const ll &n){v=ll(v)*n%mod; return *this;}
  modInt& operator/=(const ll &n){v=ll(v)*modpow(n,-1,mod)%mod; return *this;}
};
template<int mod> ostream& operator<<(ostream &os,const modInt<mod> &n){return os<<n.v;};
template<int mod> modInt<mod> operator+(const ll &n,const modInt<mod> &m){return m.v+n<mod ? m.v+n : m.v+n-mod;}
template<int mod> modInt<mod> operator-(const ll &n,const modInt<mod> &m){return n-m.v<0 ? n-m.v+mod : n-m.v;}
template<int mod> modInt<mod> operator*(const ll &n,const modInt<mod> &m){return ll(m.v)*(n%mod)%mod;}
template<int mod> modInt<mod> operator/(const ll &n,const modInt<mod> &m){return ll(m.v)*modpow(n%mod,-1,mod)%mod;}
typedef modInt<MOD> mint;
template <int mod> modInt<mod> modpow(modInt<mod> r,ll n){ modInt<mod> re(1); if(n<0)(n%=mod-1)+=mod-1; for(;n;n/=2){if(n&1) re*=r; r*=r;} return re;}
vector<mint> fact,finv,inv;
mint comb(ll n,ll r){ if(n<r||r<0)return 0; return fact[n]*finv[n-r]*finv[r];}
class Doralion{
  void Modinvs(vector<mint> &re,int n){ re.resize(n+1); re[1]=1; for(int i=2;i<=n;++i)re[i]=re[MOD%i]*(MOD-MOD/i);}
  void Facts(vector<mint> &re,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*(i+1);}
  void Factinvs(vector<mint> &re,const vector<mint> &inv,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*inv[i+1];}
public:
  Doralion(int n){ Modinvs(inv,n); Facts(fact,n); Factinvs(finv,inv,n);}
} doralion(212345);
struct UF{
  vector<int> data;
  UF(int size):data(size,-1){}
  bool unite(int x,int y){
    x=root(x); y=root(y);
    if(x!=y){
      if(data[y]<data[x]) swap(x,y);
      data[x]+=data[y]; data[y]=x;
    }
    return x!=y;
  }
  bool findSet(int x,int y){return root(x)==root(y);}
  int root(int x){return data[x]<0?x:data[x]=root(data[x]);}
  int size(int x) {return -data[root(x)];}
};

int main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);
	int n;
	cin>>n;
	vv<int> g(2*n);
	UF uf(2*n);
	rep(i,n){
		int x,y;
		cin>>x>>y; --x; --y;
		uf.unite(x,y);
		g[y].pb(x);
	}
	vector<int> es(2*n);
	vector<int> ng(2*n);
	rep(i,2*n){
		es[uf.root(i)]+=g[i].size();
		for(int x:g[i])if(x==i) ng[uf.root(i)]=1;
	}
	mint re=1;
	rep(i,2*n)if(uf.root(i)==i && uf.size(i)>1 && ng[i]==0){
		if(es[i]==uf.size(i)){
			re*=2;
		}else if(es[i]+1==uf.size(i)){
			re*=uf.size(i);
		}
	}
	cout<<re<<endl;
  return 0;
}


#include <string>
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
#include<functional>
#include<list>
#include<deque>
#include<bitset>
#include<set>
#include<map>
#include<unordered_map>
#include<unordered_set>
#include<cstring>
#include<sstream>
#include<complex>
#include<iomanip>
#include<numeric>
#include<cassert>
#define X first
#define Y second
#define pb push_back
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
#define repe(X,Y) for ((X) = 0;(X) < (Y);++(X))
#define peat(X,Y) for (;(X) < (Y);++(X))
#define all(X) (X).begin(),(X).end()
#define rall(X) (X).rbegin(),(X).rend()
#define eb emplace_back
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define Endl endl

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
template<class T> using vv=vector<vector<T>>;
template<class T> ostream& operator<<(ostream &os, const vector<T> &t) {
os<<"{"; rep(i,t.size()) {os<<t[i]<<",";} os<<"}"<<endl; return os;}
template<class S, class T> ostream& operator<<(ostream &os, const pair<S,T> &t) { return os<<"("<<t.first<<","<<t.second<<")";}
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}
#define out(args...){vector<string> a_r_g_s=s_p_l_i_t(#args, ','); e_r_r(a_r_g_s.begin(), args); }
vector<string> s_p_l_i_t(const string &s, char c){vector<string> v;int d=0,f=0;string t;for(char c:s){if(!d&&c==',')v.pb(t),t="";else t+=c;if(c=='\"'||c=='\'')f^=1;if(!f&&c=='(')++d;if(!f&&c==')')--d;}v.pb(t);return move(v);}
void e_r_r(vector<string>::iterator it) {}
template<typename T, typename... Args> void e_r_r(vector<string>::iterator it, T a, Args... args){ if(*it==" 1"||*it=="1") cerr<<endl; else cerr << it -> substr((*it)[0] == ' ', it -> length()) << " = " << a << ", "; e_r_r(++it, args...);}
const ll MOD=1e9+7;
typedef vv<int> Graph;
struct Scc{
  stack<int> S;
  vector<int> inS,low,num;
  int time;
public:
  Graph dag;
  vector<int> inv;
  vv<int> scc;
  void visit(const Graph &g, int v){
    low[v] = num[v] = ++time;
    S.push(v); inS[v]=1;
    for(const int  &w:g[v]) {
      if(!num[w]){
	visit(g,w);
	low[v]=min(low[v],low[w]);
      }else if(inS[w])
	low[v]=min(low[v],num[w]);
    }
    if(low[v]==num[v]){
      scc.push_back(vector<int>());
      while(1){
	int w = S.top(); S.pop(); inS[w]=0;
	scc.back().push_back(w);
	if (v==w) break;
      }
    }
  }
  Scc(const Graph &g) {
    const int n = g.size();
    num.resize(n); low.resize(n); inS.resize(n);
    rep(u,n) if(!num[u])
      visit(g,u);
    reverse(all(scc));

    inv.resize(n); dag.resize(n);
    rep(i,scc.size()) rep(j,scc[i].size())
      inv[scc[i][j]]=i;
    rep(i,scc.size()) rep(j,scc[i].size())
      for(auto e:g[scc[i][j]])
	if(inv[e] != i)
	  dag[i].pb(inv[e]);
  }
};
ll modpow(ll r,ll n,ll m=MOD){
  ll re=1,d=r%m;
  if(n<0)(n%=m-1)+=m-1;
  for(;n;n/=2){
    if(n&1)(re*=d)%=m;
    (d*=d)%=m;
  }
  return re;
}
template <int mod=MOD> struct modInt{
  int v;
  modInt(int v=0):v(v){}
  modInt operator+(const modInt &n){return v+n.v<mod ? v+n.v : v+n.v-mod;}
  modInt operator-(const modInt &n){return v-n.v<0 ? v-n.v+mod : v-n.v;}
  modInt operator*(const modInt &n){return ll(v)*n.v%mod;}
  modInt operator/(const modInt &n){return ll(v)*modpow(n.v%mod,-1,mod)%mod;}
  modInt operator+(const ll &n){return v+n<mod ? v+n : v+n-mod;}
  modInt operator-(const ll &n){return v-n<0 ? v-n+mod : v-n;}
  modInt operator*(const ll &n){return ll(v)*(n%mod)%mod;}
  modInt operator/(const ll &n){return ll(v)*modpow(n%mod,-1,mod)%mod;}
  modInt& operator+=(const modInt &n){v+=n.v; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const modInt &n){v-=n.v; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const modInt &n){v=ll(v)*n.v%mod; return *this;}
  modInt& operator/=(const modInt &n){v=ll(v)*modpow(n.v,-1,mod)%mod; return *this;}
  modInt& operator+=(const ll &n){v+=n; if(v>=mod) v-=mod; return *this;}
  modInt& operator-=(const ll &n){v-=n; if(v<0) v+=mod; return *this;}
  modInt& operator*=(const ll &n){v=ll(v)*n%mod; return *this;}
  modInt& operator/=(const ll &n){v=ll(v)*modpow(n,-1,mod)%mod; return *this;}
};
template<int mod> ostream& operator<<(ostream &os,const modInt<mod> &n){return os<<n.v;};
template<int mod> modInt<mod> operator+(const ll &n,const modInt<mod> &m){return m.v+n<mod ? m.v+n : m.v+n-mod;}
template<int mod> modInt<mod> operator-(const ll &n,const modInt<mod> &m){return n-m.v<0 ? n-m.v+mod : n-m.v;}
template<int mod> modInt<mod> operator*(const ll &n,const modInt<mod> &m){return ll(m.v)*(n%mod)%mod;}
template<int mod> modInt<mod> operator/(const ll &n,const modInt<mod> &m){return ll(m.v)*modpow(n%mod,-1,mod)%mod;}
typedef modInt<MOD> mint;
template <int mod> modInt<mod> modpow(modInt<mod> r,ll n){ modInt<mod> re(1); if(n<0)(n%=mod-1)+=mod-1; for(;n;n/=2){if(n&1) re*=r; r*=r;} return re;}
vector<mint> fact,finv,inv;
mint comb(ll n,ll r){ if(n<r||r<0)return 0; return fact[n]*finv[n-r]*finv[r];}
class Doralion{
  void Modinvs(vector<mint> &re,int n){ re.resize(n+1); re[1]=1; for(int i=2;i<=n;++i)re[i]=re[MOD%i]*(MOD-MOD/i);}
  void Facts(vector<mint> &re,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*(i+1);}
  void Factinvs(vector<mint> &re,const vector<mint> &inv,int n){ re.resize(n+1); re[0]=1; rep(i,n)re[i+1]=re[i]*inv[i+1];}
public:
  Doralion(int n){ Modinvs(inv,n); Facts(fact,n); Factinvs(finv,inv,n);}
} doralion(212345);

int main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);
	int n;
	cin>>n;
	vv<int> g(2*n);
	rep(i,n){
		int x,y;
		cin>>x>>y; --x; --y;
		if(x!=y)
			g[y].pb(x);
	}
	Scc h(g);
	vector<int> usd(2*n);
	vector<int> ind(2*n);
	rep(i,h.dag.size())for(int v:h.dag[i]) ++ind[v];
	function<int(int)> dfs=[&](int v){
		int re=1;
		for(int w:h.dag[v]) re+=dfs(w);
		return re;
	};
	mint re=1;
	rep(i,2*n){
		int id=h.inv[i];
		if(ind[id] || MX(usd[id],1)==0) continue;
		if(h.dag[id].size()==0 && h.scc[id].size()==1) continue;
		int sz=dfs(id);
		if(h.scc[id].size()>1){
			re*=2;
		}else{
			re*=sz;
		}
	}
	cout<<re<<endl;
  return 0;
}