#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <climits>
#include <cstdlib>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <list>
#include <unordered_map>
#include <bitset>
#include <algorithm>
#define ll long long int
#define e() cout << endl;
#define MA INT_MAX
#define MI INT_MIN
#define MOD 1000000007;
#define ppi pair <int,int>
#define scn(n) scanf("%d",&n)
#define vvi(n,m,x) vector <vector <int> > v(n,vector <int> (m,x));
#define cp(x,y) cout << "Case : " << x << " " << y << endl;
using namespace std;
int main()
{
	int n;
	cin >> n;
	if(n <= 3)
	{
		cout << "NO\n";
		return 0;
	}

	cout << "YES\n";
	if(n % 2 == 0)
	{
		int cnt = 0;
		for(int i = n;i > 4;i -= 2)
		{
			cout << i << " - " << (i - 1) << " = 1\n";
			cnt++;
		}
		//cout << "no of cnt : " << cnt << endl;
		for(int i = 1;i <= cnt;i++)
			cout << "1 * 1 = 1\n";

		cout << "1 * 2 = 2\n2 * 4 = 8\n8 * 3 = 24\n";
	}
	else if(n == 5)
	{
		cout << "5 - 3 = 2\n2 * 4 = 8\n1 + 2 = 3\n8 * 3 = 24\n";
		return 0;
	}
	else
	{
		int cnt = 0;
		for(int i = n;i > 7;i -= 2)
		{
			cout << i << " - " << (i - 1) << " = 1\n";
			cnt++;
		}

		for(int i = 1;i <= cnt;i++)
			cout << "1 * 1 = 1\n";

		cout << "7 - 3 = 4\n5 - 2 = 3\n6 - 4 = 2\n1 * 2 = 2\n2 * 4 = 8\n8 * 3 = 24\n";
	}
 	return 0;
}


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <climits>
#include <cstdlib>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <list>
#include <unordered_map>
#include <bitset>
#include <algorithm>
#define ll long long int
#define e() cout << endl;
#define MA INT_MAX
#define MI INT_MIN
#define MOD 1000000007;
#define ppi pair <int,int>
#define scn(n) scanf("%d",&n)
#define vvi(n,m,x) vector <vector <int> > v(n,vector <int> (m,x));
#define cp(x,y) cout << "Case : " << x << " " << y << endl;
using namespace std;
int main()
{
	int n;
	cin >> n;
	if(n <= 3 || (n % 2))
	{
		cout << "NO\n";
		return 0;
	}

	cout << "YES\n";
	int cnt = 0;
	for(int i = n;i > 4;i -= 2)
	{
		cout << i << " - " << (i - 1) << " = 1\n";
		cnt++;
	}
	//cout << "no of cnt : " << cnt << endl;
	for(int i = 1;i <= cnt;i++)
		cout << "1 * 1 = 1\n";

	cout << "1 * 2 = 2\n2 * 4 = 8\n8 * 3 = 24\n";
 	return 0;
}


#include <iostream>
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <climits>
#include <cstdlib>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <list>
#include <unordered_map>
#include <bitset>
#include <algorithm>
#define ll long long int
#define e() cout << endl;
#define MA INT_MAX
#define MI INT_MIN
#define MOD 1000000007;
#define ppi pair <int,int>
#define scn(n) scanf("%d",&n)
#define vvi(n,m,x) vector <vector <int> > v(n,vector <int> (m,x));
#define cp(x,y) cout << "Case : " << x << " " << y << endl;
using namespace std;
int main()
{
	int n;
	cin >> n;
	if(n <= 3 || (n % 2))
		cout << "NO\n";

	cout << "YES\n";
	int cnt = 0;
	for(int i = n;i > 4;i -= 2)
	{
		cout << i << " - " << (i - 1) << " = 1\n";
		cnt++;
	}
	//cout << "no of cnt : " << cnt << endl;
	for(int i = 1;i <= cnt;i++)
		cout << "1 * 1 = 1\n";

	cout << "1 * 2 = 2\n2 * 4 = 8\n8 * 3 = 24\n";
 	return 0;
}


#include <bits/stdc++.h>

using namespace std;
int ar1[2000000];
int ar2[2000000];
 int a[2000000];
pair<int ,int >p[200000];
string str[110];
int min(int x,int y,int z){
    int miin=x;
    if(miin<y)miin=y;
    if(miin<z)miin=z;
    return miin;}

int main(){
       int n;
       cin>>n;
       int i;
       if(n<4){cout<<"NO";return 0;}
       cout<<"YES"<<endl;
       for(i=n ;i>5;i-=2)
       cout<<i<<" - "<<i-1<<" = 1\n1 * 1 = 1\n";
       if (i==4) printf("1 + 2 = 3\n3 + 3 = 6\n4 * 6 = 24\n");
       if (i==5) printf("1 * 5 = 5\n5 - 2 = 3\n3 + 3 = 6\n4 * 6 = 24\n");

     return 0;
}


#include <bits/stdc++.h>

using namespace std;
int ar1[2000000];
int ar2[2000000];
 int a[2000000];
pair<int ,int >p[200000];
string str[110];
int min(int x,int y,int z){
    int miin=x;
    if(miin<y)miin=y;
    if(miin<z)miin=z;
    return miin;}

int main(){
       int n;
       cin>>n;
       int i;
       if(n<4){cout<<"NO";return 0;}
       cout<<"YES"<<endl;
       for(i=n ;i>5;i-=2)
       cout<<i<<" - "<<i-1<<" = 1\n1 + 1 = 2\n";;
       if(i==5){cout<<"5 * 4 = 20\n2 + 2 = 4\n4 + 20 = 24";}
       else  cout<<"3 * 2 = 6\n2 +2 = 4\n4 * 6 = 24";

     return 0;
}


#include <bits/stdc++.h>

using namespace std;
int ar1[2000000];
int ar2[2000000];
 int a[2000000];
pair<int ,int >p[200000];
string str[110];
int min(int x,int y,int z){
    int miin=x;
    if(miin<y)miin=y;
    if(miin<z)miin=z;
    return miin;}

int main(){
       int n;
       cin>>n;
       int i;
       if(n<4){cout<<"NO";return 0;}
       cout<<"YES"<<endl;
       for(i=n ;i>5;i-=2)
       cout<<i<<"-"<<i-1<<"=1\n1+1=2\n";;
       if(i==5){cout<<"5*4=20\n2+2=4\n4+20=24";}
       else  cout<<"3*2=6\n2+2=4\n4*6=24";

     return 0;
}


#include <bits/stdc++.h>

using namespace std;
int ar1[2000000];
int ar2[2000000];
 int a[2000000];
pair<int ,int >p[200000];
string str[110];
int min(int x,int y,int z){
    int miin=x;
    if(miin<y)miin=y;
    if(miin<z)miin=z;
    return miin;}

int main(){
       int n;
       cin>>n;
       int i;
       if(n<4){cout<<"NO";return 0;}
       cout<<"YES"<<endl;
       for(i=n ;i>5;i-=2)
       cout<<i<<" - "<<i-1<<" = 1\n1 + 1 = 2\n";;
       if(i==5){cout<<"5 * 4 = 20\n2 + 2 = 4\n4 + 20 = 24";}
       else  cout<<"3 * 2 = 6\n2 + 2 = 4\n4 * 6 = 24";

     return 0;
}


#include <bits/stdc++.h>

using namespace std;
int ar1[2000000];
int ar2[2000000];
 int a[2000000];
pair<int ,int >p[200000];
string str[110];
int min(int x,int y,int z){
    int miin=x;
    if(miin<y)miin=y;
    if(miin<z)miin=z;
    return miin;}

int main(){
       int n;
       cin>>n;
       int i;
       if(n<4){cout<<"NO";return 0;}
       cout<<"YES"<<endl;
       for(i=n ;i>5;i-=2)
       cout<<i<<" - "<<i-1<<" = 1\n1+1=2\n";;
       if(i==5){cout<<"5 * 4 = 20\n2 + 2 = 4\n4 + 20 = 24";}
       else  cout<<"3 * 2 = 6\n2 +2 = 4\n4 * 6 = 24";

     return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define pii pair<ll, ll>
#define pb push_back
#define poop pop_back

using namespace std;

int main()
{
    ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);

    int n;
    cin >> n;
    if(n <= 3)
        return cout << "NO", 0;
    cout << "YES" << endl;
    if(n % 2 == 1)
    {
        cout << "5 - 1 = 4" << endl << "4 - 2 = 2" << endl << "3 * 2 = 6" << endl << "6 * 4 = 24" << endl;
        for(int i = 6; i <= n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;

    }
    else
    {
        int ss = 1;
        for(int i = 2; i <= 4; i++)
        {
            cout << ss << " * " << i << " = " << ss * i << endl;
            ss *= i;
        }
        for(int i = 5; i <= n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define pii pair<ll, ll>
#define pb push_back
#define poop pop_back

using namespace std;

int main()
{
    ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);

    int n;
    cin >> n;
    if(n <= 3)
        return cout << "NO", 0;
    cout << "YES" << endl;
    if(n % 2 == 1)
    {
        cout << "5 - 1 = 4" << endl << "4 / 2 = 2" << endl << "3 * 2 = 6" << endl << "6 * 4 = 24" << endl;
        for(int i = 6; i <= n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;

    }
    else
    {
        int ss = 1;
        for(int i = 2; i <= 4; i++)
        {
            cout << ss << " * " << i << " = " << ss * i << endl;
            ss *= i;
        }
        for(int i = 5; i <= n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;
    }

    return 0;
}


#include <bits/stdc++.h>
#define ll long long
#define F first
#define S second
#define pii pair<ll, ll>
#define pb push_back
#define poop pop_back

using namespace std;

int main()
{
    ios::sync_with_stdio(false), cout.tie(0), cin.tie(0);

    int n;
    cin >> n;
    if(n <= 3)
        return cout << "NO", 0;
    cout << "YES" << endl;
    if(n % 2 == 1)
    {
        cout << "5 - 1 = 4" << endl << "4 / 2 = 2" << endl << "3 * 2 = 6" << endl << "6 * 4 = 24" << endl;
        for(int i = 6; i < n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;

    }
    else
    {
        int ss = 1;
        for(int i = 2; i <= 4; i++)
        {
            cout << ss << " * " << i << " = " << ss * i << endl;
            ss *= i;
        }
        for(int i = 5; i <= n; i += 2)
            cout << i + 1 << " - " << i << " = 1" << endl << "24 * 1 = 24" << endl;
    }

    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run()
{
    if(n==3)
    {
        cout<<"3 - 1 = 2\n2 * 2 = 4\n4 * 6 = 24\n";
        return ;
    }
    if(n==4)
    {
        cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
        return ;
    }
    cout<<n<<" - "<<n-1<<" = 1\n";
    n-=2;
    run();
}
int main()
{
    islam();
    cin>>n;
    ll a=n-4;
    a/=2;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    else
        cout<<"YES\n";
    if(n==5)
    {
        cout<<"3 - 1 = 2\n2 * 2 = 4\n4 * 5 = 20\n20 + 4 = 24\n";
        return 0;
    }
    run();
    while(a--)
    {
        cout<<"24 * 1 = 24\n";
    }

    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run()
{
    if(n==4)
    {
        cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
        return ;
    }
    if(n==5)
    {
        cout<<"5 - 3 = 2\n2 * 4 = 8\n1 + 2 = 3\n8 * 3 = 24\n";
        return ;
    }
    cout<<n<<" - "<<n-1<<" = 1\n";
    n--;
    run();
}
int main()
{
    islam();
    cin>>n;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    cout<<"YES\n";
    run();
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run()
{
    if(n==4)
        return ;
    if(n==7)
    {
        cout<<"7 - 6 = 1\n5 - 4 = 1\n24 * 1 = 24\n";
        return ;
    }
    cout<<n<<" - "<<n-1<<" = 1\n24 * 1 = 24\n";
    n-=2;
    run();
}
int main()
{
    islam();
    cin>>n;
    ll a=n-4;
    a/=2;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    else
        cout<<"YES\n";
    if(n==5)
    {
        cout<<"3 - 1 = 2\n2 * 2 = 4\n4 * 5 = 20\n20 + 4 = 24\n";
        return 0;
    }
    cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
    run();
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run(int x)
{
    if(x>n)
        return ;
    if(x==7)
    {
        cout<<"7 - 6 = 1\n5 - 4 = 1\n24 * 1 = 24\n";
        if(n==7)
            return ;
    }
    if(x!=7)
    cout<<x<<" - "<<x-1<<" = 1\n24 * 1 = 24\n";
    x+=2;
    run(x);
}
int main()
{
    islam();
    cin>>n;
    ll a=n-4;
    a/=2;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    else
        cout<<"YES\n";
    if(n==5)
    {
        cout<<"3 - 1 = 2\n2 * 2 = 4\n4 * 5 = 20\n20 + 4 = 24\n";
        return 0;
    }
    if(n%2)
        run(7);
    else
    run(6);
    cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run()
{
    if(n<4)
        return ;
    if(n==4)
    {
        cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
        return ;
    }
    cout<<n<<" - "<<n-1<<" = 1\n";
    if(n>5)
    n-=2;
    else
        n--;
    run();
}
int main()
{
    islam();
    cin>>n;
    ll a=n-4;
    a/=2;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    else
        cout<<"YES\n";
    run();
    while(a--)
    {
        cout<<"24 * 1 = 24\n";
    }

    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run()
{
    if(n==4)
    {
        cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
        return ;
    }
    if(n==5)
    {
        cout<<"5 - 3 = 2\n2 * 4 = 8\n1 + 2 = 3\n8 * 3 = 24\n";
        return ;
    }
    cout<<n<<" - "<<n-1<<" = 1\n1 * 1 = 1\n";
    n-=2;
    run();
}
int main()
{
    islam();
    cin>>n;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    cout<<"YES\n";
    run();
    return 0;
}


#include<bits/stdc++.h>
#define ll long long
using namespace std;
void islam()
{
    cin.tie(0);
    std::ios::sync_with_stdio(0);
  //  freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
}
ll n;
void run(int x)
{
    if(x>n)
        return ;
    if(x==7)
    {
        cout<<"7 - 6 = 1\n5 - 4 = 1\n1 * 1 = 1\n";
        if(n==7)
            return ;
    }
    if(x!=7)
    cout<<x<<" - "<<x-1<<" = 1\n1 * 1 = 1\n";
    x+=2;
    run(x);
}
int main()
{
    islam();
    cin>>n;
    ll a=n-4;
    a/=2;
    if(n<4)
    {
        cout<<"NO";
        return 0;
    }
    else
        cout<<"YES\n";
    if(n==5)
    {
        cout<<"3 - 1 = 2\n2 * 2 = 4\n4 * 5 = 20\n20 + 4 = 24\n";
        return 0;
    }
    if(n%2)
        run(7);
    else
    run(6);
    cout<<"4 * 3 = 12\n2 * 1 = 2\n12 * 2 = 24\n";
    return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <stack>
#define ll long long

using namespace std;
vector <vector <int> > g;
vector <int> used, start;
vector <ll> dp;
ll mod = 1e9 + 7;
ll dfs(int v) {
	used[v] = 1;
	ll cur = 0;
	dp[v] = (ll)1;
	if (g[v].size() == 0)
		return 1;
	for (int u : g[v]) {
		if (used[u] == 0) {
			cur += dfs(u);
			dp[v] *= dp[u];
			dp[v] %= mod;
		}
	}
	dp[v] += cur;
	dp[v] %= mod;
	return cur;
}

void dfs2(int v) {
	used[v] = 1;
	for (int u : g[v])
		if (!used[u])
			dfs2(u);
}
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	g.resize(2 * n);
	used.resize(2 * n);
	dp.resize(2 * n);
	start.resize(2 * n, 1);
	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		if (v != u)
			g[u].push_back(v), start[v] = 0;

	}
	ll ans = 1;
	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (start[i])) {
			dfs(i);
			ans *= dp[i];
			ans %= mod;
		}
	}

	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (!start[i]) && (g[i].size() != 0))
			dfs2(i), ans = (ans * 2) % mod;
	}
	cout << ans;
	return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <stack>
#define ll long long

using namespace std;
vector <vector <int> > g;
vector <int> used, start;
vector <ll> dp;
ll mod = 1e9 + 7;
ll dfs(int v) {
	used[v] = 1;
	int cur = 1;
	for (int u : g[v]) {
		if (used[u] == 0) {
			cur += dfs(u);
		}
	}
	return cur;
}

void dfs2(int v) {
	used[v] = 1;
	for (int u : g[v])
		if (!used[u])
			dfs2(u);
}
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	g.resize(2 * n);
	used.resize(2 * n);
	dp.resize(2 * n);
	start.resize(2 * n, 1);
	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		if (v != u)
			g[u].push_back(v), start[v] = 0;

	}
	ll ans = 1;
	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (start[i])) {
			ll k = 1;
			ans *= dfs(i);
			ans %= mod;
		}
	}

	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (!start[i]) && (g[i].size() != 0))
			dfs2(i), ans = (ans * 2) % mod;
	}
	cout << ans;
	return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <stack>
#define ll long long

using namespace std;
vector <vector <int> > g;
vector <int> used, start;
vector <ll> dp;
ll mod = 1e9 + 7;
ll dfs(int v) {
	used[v] = 1;
	ll cur = 0;
	dp[v] = (ll)1;
	if (g[v].size() == 0)
		return 1;
	for (int u : g[v]) {
		if (used[u] == 0) {
			cur += dfs(u);
			dp[v] *= dp[u];
			dp[v] %= mod;
		}
	}
	dp[v] += cur;
	dp[v] %= mod;
	return cur;
}

void dfs2(int v) {
	used[v] = 1;
	for (int u : g[v])
		if (!used[u])
			dfs2(u);
}
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	g.resize(2 * n);
	used.resize(2 * n);
	dp.resize(2 * n);
	start.resize(2 * n, 1);
	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		if (v != u)
			g[u].push_back(v);
		start[v] = 0;

	}
	ll ans = 1;
	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (start[i])) {
			dfs(i);
			ans *= dp[i];
			ans %= mod;
		}
	}

	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (!start[i]) && (g[i].size() != 0))
			dfs2(i), ans = (ans * 2) % mod;
	}
	cout << ans;
	return 0;
}


#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdio>

#define ll long long

using namespace std;

vector <vector <int> > g, g2, gcomp;
vector <int> comp, s_c, used, top_sort;
int k_comp = 0;
ll mod = (ll)1e9 + 7;

void dfs_top_sort(int v) {
	used[v] = 1;

	for (int u : g[v]) {
		if (!used[u])
			dfs_top_sort(u);
	}

	top_sort.push_back(v);
}

void dfs_comp(int v) {
	comp[v] = k_comp;
	used[v] = 1;
	s_c[k_comp]++;

	for (int u : g2[v]) {
		if (!used[u])
			dfs_comp(u);
	}
}

int get_size(int v) {
	int s = 1;
	used[v] = s_c[v];

	for (int u : gcomp[v]) {
		if (!used[u])
			s += get_size(u);
	}

	return s;
}

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

	int n;
	cin >> n;
	g.resize(2 * n);
	g2.resize(2 * n);
	comp.resize(2 * n);
	used.resize(2 * n);

	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		g[u].push_back(v);
		g2[v].push_back(u);
	}

	for (int v = 0; v < 2 * n; v++) {
		if (used[v] == 0)
			dfs_top_sort(v);
	}

	reverse(top_sort.begin(), top_sort.end());
	used.assign(2 * n, 0);

	for (int i = 0; i < 2 * n; i++) {
		int v = top_sort[i];

		if (!used[v]) {
			s_c.push_back(0);
			dfs_comp(v);
			k_comp++;
		}
	}

	vector <int> start(k_comp, 1);
	gcomp.resize(k_comp);

	for (int v = 0; v < 2 * n; v++) {
		for (int u : g[v]) {
			if (comp[v] == comp[u])
				continue;
			start[u] = 0;
			gcomp[v].push_back(u);
		}
	}

	used.assign(k_comp, 0);
	ll ans = 1;

	for (int v = 0; v < k_comp; v++) {
		if ((used[v]) || (!start[v]))
			continue;

		if (s_c[v] > 1)
			ans = (ans * (ll)2) % mod;
		else
			ans = (ans * (ll)get_size(v)) % mod;
	}

	cout << ans;

	//system("pause");
	return 0;
}


#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <queue>
#include <stack>
#define ll long long

using namespace std;
vector <vector <int> > g;
vector <int> used, start;
vector <ll> dp;
ll mod = ll(1e9) + 7;
ll dfs(int v) {
	used[v] = 1;
	ll cur = 0;
	dp[v] = (ll)1;
	if (g[v].size() == 0)
		return 1;
	for (int u : g[v]) {
		if (used[u] == 0) {
			cur += dfs(u);
			dp[v] *= dp[u];
			dp[v] %= mod;
		}
	}
	dp[v] += cur;
	return cur;
}

void dfs2(int v) {
	used[v] = 1;
	for (int u : g[v])
		if (!used[u])
			dfs2(u);
}
int main() {
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int n;
	cin >> n;
	g.resize(2 * n);
	used.resize(2 * n);
	dp.resize(2 * n);
	start.resize(2 * n, 1);
	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		if (v != u)
			g[u].push_back(v);
		start[v] = 0;

	}
	ll ans = 1;
	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (start[i]) && (g[i].size() != 0)) {
			dfs(i);
			ans *= dp[i];
			ans %= mod;
		}
	}

	for (int i = 0; i < 2 * n; i++) {
		if ((!used[i]) && (!start[i]) && (g[i].size() != 0))
			dfs2(i), ans = (ans * 2) % mod;
	}
	cout << ans;
	return 0;
}


#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdio>

#define ll long long

using namespace std;

vector <vector <int> > g, g2, gcomp;
vector <int> comp, s_c, used, top_sort;
int k_comp = 0;
ll mod = (ll)1e9 + 7;

void dfs_top_sort(int v) {
	used[v] = 1;

	for (int u : g[v]) {
		if (!used[u])
			dfs_top_sort(u);
	}

	top_sort.push_back(v);
}

void dfs_comp(int v) {
	comp[v] = k_comp;
	used[v] = 1;
	s_c[k_comp]++;

	for (int u : g2[v]) {
		if (!used[u])
			dfs_comp(u);
	}
}

int get_size(int v) {
	int s = 1;
	used[v] = s_c[v];

	for (int u : gcomp[v]) {
		if (!used[u])
			s += get_size(u);
	}

	return s;
}

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

	int n;
	cin >> n;
	g.resize(2 * n);
	g2.resize(2 * n);
	comp.resize(2 * n);
	used.resize(2 * n);

	for (int i = 0; i < n; i++) {
		int v, u;
		cin >> v >> u;
		v--;
		u--;
		g[u].push_back(v);
		g2[v].push_back(u);
	}

	for (int v = 0; v < 2 * n; v++) {
		if (used[v] == 0)
			dfs_top_sort(v);
	}

	reverse(top_sort.begin(), top_sort.end());
	used.assign(2 * n, 0);

	for (int i = 0; i < 2 * n; i++) {
		int v = top_sort[i];

		if (!used[v]) {
			s_c.push_back(0);
			dfs_comp(v);
			k_comp++;
		}
	}

	vector <int> start(k_comp, 1);
	gcomp.resize(k_comp);

	for (int v = 0; v < 2 * n; v++) {
		for (int u : g[v]) {
			if ((comp[v] == comp[u]) && (v != u))
				continue;
			start[comp[u]] = 0;
			gcomp[comp[v]].push_back(comp[u]);
		}
	}

	used.assign(k_comp, 0);
	ll ans = 1;

	for (int v = 0; v < k_comp; v++) {
		if ((used[v]) || (!start[v]))
			continue;

		if (s_c[v] > 1)
			ans = (ans * (ll)2) % mod;
		else
			ans = (ans * (ll)get_size(v)) % mod;
	}

	cout << ans;

	system("pause");
	return 0;
}


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

int parent[200005],sizex[200005],cycle[200005],done[200005],self[200005];

int find(int n){
	if(parent[n]==n)
	return n;
	return find(parent[n]);
}

void merge(int u,int v){
	u=find(u);
	v=find(v);

	if(sizex[u]<sizex[v])
	swap(u,v);

	parent[v]=u;
	sizex[u]+=sizex[v];
	self[u]|=self[v];
}

int main(){
	int n;
	scanf("%d",&n);

	for (int i=1;i<=2*n;i++){
		parent[i]=i;
		sizex[i]=1;
	}

	for (int i=1;i<=n;i++){
		int a,b;
		scanf("%d %d",&a,&b);

		if(a==b){
			self[find(a)]=1;
			continue;
		}

		if(find(a)!=find(b))
		merge(a,b);

		else
		cycle[find(a)]=1;
	}

	long long ans=1,mod=1e9+7;

	for (int i=1;i<=2*n;i++){
		int x=find(i);
		if(!done[x]){
			done[x]=1;

			if(self[x])
			continue;

			if(cycle[x]){
				ans=(ans*2)%mod;
			}

			else ans=((long long)ans*sizex[x])%mod;
		}
	}

	printf("%lld",ans);

}


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

int parent[200005],sizex[200005],cycle[200005],done[200005];

int find(int n){
	if(parent[n]==n)
	return n;
	return parent[n];
}

void merge(int u,int v){
	u=find(u);
	v=find(v);

	if(sizex[u]<sizex[v])
	swap(u,v);

	parent[v]=u;
	sizex[u]+=sizex[v];
}

int main(){
	int n;
	scanf("%d",&n);

	for (int i=1;i<=2*n;i++){
		parent[i]=i;
		sizex[i]=1;
	}

	for (int i=1;i<=n;i++){
		int a,b;
		scanf("%d %d",&a,&b);

		if(a==b)
		continue;

		if(find(a)!=find(b))
		merge(a,b);

		else
		cycle[find(a)]=1;
	}

	long long ans=1,mod=1e9+7;

	for (int i=1;i<=n;i++){
		int x=find(i);
		if(!done[x]){
			done[x]=1;
			if(cycle[x]){
				ans=(ans*2)%mod;
			}

			else ans=(ans*sizex[x])%mod;
		}
	}

	printf("%lld",ans);

}


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

vector<int>v[200005];
int visited[200005];

int loop,cycle,cnt;

void dfs(int node,int par){
	if(visited[node]){
		cycle=1;
		return ;
	}
	visited[node]=1;
	cnt++;
	for (int i=0;i<v[node].size();i++){
		if(v[node][i]==par)
		continue;

		if(v[node][i]==node)
		loop=1;

		dfs(v[node][i],node);
	}

}

int main(){
	int n;
	scanf("%d",&n);

	for (int i=1;i<=n;i++){
		int a,b;
		scanf("%d %d",&a,&b);
		v[a].push_back(b);
		v[b].push_back(a);
	}

	long long ans=1,mod=1e9+7;
	for (int i=1;i<=2*n;i++){
		if(visited[i])
		continue;

		loop=0;
		cycle=0;
		cnt=0;
		dfs(i,0);

		if(loop)
		continue;
		if(cycle)
		ans=(ans*2LL)%mod;

		else ans=(ans*cnt*1LL)%mod;
	}

	printf("%lld",ans);

}


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

int parent[200005],sizex[200005],cycle[200005],done[200005],self[200005];

int find(int n){
	if(parent[n]==n)
	return n;
	return find(parent[n]);
}

void merge(int u,int v){
	u=find(u);
	v=find(v);

	if(sizex[u]<sizex[v])
	swap(u,v);

	parent[v]=u;
	sizex[u]+=sizex[v];
	self[u]|=self[v];
}

int main(){
	int n;
	scanf("%d",&n);

	for (int i=1;i<=2*n;i++){
		parent[i]=i;
		sizex[i]=1;
	}

	for (int i=1;i<=n;i++){
		int a,b;
		scanf("%d %d",&a,&b);

		if(a==b){
			self[find(a)]=1;
			continue;
		}

		if(find(a)!=find(b))
		merge(a,b);

		else
		cycle[find(a)]=1;
	}

	long long ans=1,mod=1e9+7;

	for (int i=1;i<=2*n;i++){
		int x=find(i);
		if(!done[x]){
			done[x]=1;

			if(self[x])
			continue;

			if(cycle[x]){
				ans=(ans*2)%mod;
			}

			else ans=(ans*sizex[x])%mod;
		}
	}

	printf("%lld",ans);

}


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

int parent[200005],sizex[200005],cycle[200005],done[200005],self[200005];

int find(int n){
	if(parent[n]==n)
	return n;
	return find(parent[n]);
}

void merge(int u,int v){
	u=find(u);
	v=find(v);

	if(sizex[u]<sizex[v])
	swap(u,v);

	parent[v]=u;
	sizex[u]+=sizex[v];
	self[u]|=self[v];
}

int main(){
	int n;
	scanf("%d",&n);

	for (int i=1;i<=2*n;i++){
		parent[i]=i;
		sizex[i]=1;
	}

	for (int i=1;i<=n;i++){
		int a,b;
		scanf("%d %d",&a,&b);

		if(a==b){
			self[find(a)]=1;
			continue;
		}

		if(find(a)!=find(b))
		merge(a,b);

		else
		cycle[find(a)]=1;
	}

	long long ans=1,mod=1e9+7;

	for (int i=1;i<=n;i++){
		int x=find(i);
		if(!done[x]){
			done[x]=1;

			if(self[x])
			continue;

			if(cycle[x]){
				ans=(ans*2)%mod;
			}

			else ans=(ans*sizex[x])%mod;
		}
	}

	printf("%lld",ans);

}


#include <cstdio>
#include <vector>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], vis[200010], inamovible[200010];
vector<int> v[200010];

ll cp;
void DFS(int u)
{
    if(vis[u])
        return;
    vis[u] = true;
    cp++;

    for(int neigh : v[u])
        DFS(neigh);
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if(a == b)
            inamovible[a] = true;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && (!is_left[i] || inamovible[i]))
        {
            cp = 0;
            DFS(i);
            if(!inamovible[i])
                ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        if(is_left[i] && !vis[i])
        {
            DFS(i);
            ans = (2*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], inamovible[200010];
int vis[200010];
vector<int> v[200010];

int act;
ll cp;
void DFS(int u)
{
    if(vis[u])
        return;
    vis[u] = act;
    cp++;

    for(int neigh : v[u])
        DFS(neigh);
}

ll f;
void DFS2(int u)
{
    if(vis[u])
    {
        if(vis[u] != act)
            f = 1;
        return;
    }

    vis[u] = act;

    for(int neigh : v[u])
        DFS2(neigh);
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf(" %d %d", &a, &b);
        if(a == b)
            inamovible[a] = true;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && (!is_left[i] || inamovible[i]))
        {
            cp = 0;
            act++;
            DFS(i);
            if(!inamovible[i])
                ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && !vis[i])  //cycles non inamovibles
        {
            f = 2;
            act++;
            DFS2(i);
            /*printf("%d: ", i);
            for(int j = 1; j <= 2*N; j++)
                printf("%d", vis[j]);
            printf("\n");*/

            ans = (f*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], vis[200010];
vector<int> v[200010];

ll cp;
void DFS(int u)
{
    if(vis[u])
        return;
    vis[u] = true;
    cp++;

    for(int neigh : v[u])
        DFS(neigh);
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if(a == b)
            continue;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && !is_left[i])
        {
            cp = 0;
            DFS(i);
            ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        if(is_left[i] && !vis[i])
        {
            DFS(i);
            ans = (2*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], vis[200010], inamovible[200010];
vector<int> v[200010];

ll cp;
void DFS(int u)
{
    if(vis[u])
        return;
    vis[u] = true;
    cp++;

    for(int neigh : v[u])
        DFS(neigh);
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        if(a == b)
            inamovible[a] = true;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && (!is_left[i] || inamovible[i]))
        {
            cp = 0;
            DFS(i);
            if(!inamovible[i])
                ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && !vis[i])
        {
            DFS(i);
            ans = (2*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>
#include <stack>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], inamovible[200010], vis[200010];
vector<int> v[200010], v2[200010];

ll cp;

stack<int> s;
void DFS(int start)
{
    s.push(start);

    while(!s.empty())
    {
        int u = s.top();
        s.pop();

        if(vis[u])
            continue;

        vis[u] = true;
        cp++;

        for(int neigh : v[u])
            s.push(neigh);
    }
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf(" %d %d", &a, &b);
        if(a == b)
            inamovible[a] = true;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);

        if(a != b)
            v2[a].PB(b);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && (!is_left[i] || inamovible[i]))
        {
            cp = 0;
            DFS(i);
            if(!inamovible[i])
                ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        for(int u : v2[i])
            v[i].PB(u);

    /*for(int i = 1; i <= 2*N; i++)
        for(int u : v[i])
            printf("%d -> %d\n", i, u);*/

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && !vis[i])  //cycles non inamovibles
        {
            DFS(i);
            ans = (2*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>
#include <stack>

#define PB push_back

using namespace std;

typedef long long ll;
const ll MOD = 1000*1000*1000 + 7;

int N;
bool is_left[200010], is_right[200010], inamovible[200010], vis[200010];
vector<int> v[200010], vt[200010];

ll cp;

stack<int> s;
void DFS(int start)
{
    s.push(start);

    while(!s.empty())
    {
        int u = s.top();
        s.pop();

        if(vis[u])
            continue;
        vis[u] = true;
        cp++;

        for(int neigh : v[u])
            s.push(neigh);
    }
}

int main()
{
    scanf("%d", &N);
    ll ans = 1;
    for(int i = 0; i < N; i++)
    {
        int a, b;
        scanf(" %d %d", &a, &b);
        if(a == b)
            inamovible[a] = true;

        is_left[a] = true;
        is_right[b] = true;
        v[b].PB(a);
        vt[a].PB(b);
    }

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && (!is_left[i] || inamovible[i]))
        {
            cp = 0;
            DFS(i);
            if(!inamovible[i])
                ans = (ans*cp)%MOD;
        }

    for(int i = 1; i <= 2*N; i++)
        for(int u : vt[i])
            v[u].PB(i);

    for(int i = 1; i <= 2*N; i++)
        if(is_right[i] && !vis[i])  //cycles non inamovibles
        {
            DFS(i);
            ans = (2*ans)%MOD;
        }

    printf("%I64d\n", ans);
    return 0;
}


#include <cstdio>
#include <vector>
typedef std::vector<int> vin;
const int MAXN = 2E5+5;
const int MOD  = 1E9+7;
bool dual[MAXN]{ };
int final[MAXN]{ };
int graph[MAXN]{ }; // Single Child
bool  low[MAXN]{ };
int   val[MAXN]{ };
bool  vis[MAXN]{ };
int N, ret=1;

vin G[MAXN]{ };

int dfs(int cur)
{
	if(!graph[cur]) // Hit the Base of a Leaf
	{
		// return val[cur];
		final[cur] += val[cur];
		// dual[cur] = true;
		return 0;
	}
	G[graph[cur]].push_back(cur); // Reverse Graph
	if(vis[graph[cur]])
	{
		if(!graph[graph[cur]]) // Sink Node with Multiple Sources
		{
			final[graph[cur]] += val[cur];
			// dual[graph[cur]] = false;
		}
		return 0;	// Entering Old Loop (multiple roots) ->O<-
	}
	if(val[graph[cur]])	// Current Self-Loop or Cycle
		return (cur == graph[cur]) ? 1 : 2;	// Single Rotation
	val[graph[cur]] = val[cur] + 1;
	int res = dfs(graph[cur]);
	vis[graph[cur]] = true;
	return res;
}

int dfs2(int cur)
{
	int rkt = 1;
	for(auto nxt: G[cur])
		rkt += dfs2(nxt);
	return rkt;
}

int main()
{
	// freopen("in.in", "r", stdin);
	scanf("%d", &N);
	for(int i = 0; i < N; ++i)
	{
		int u, v;
		scanf(" %d%d", &u, &v);
		// if(u == v) continue; // Allow Self-Loops!
		graph[u] = v;
		low[v] = true;
	}
	N <<= 1;
	for(int i = 1; i <= N; ++i) if(!low[i]) // Root of Tree
	{	// Only Chains + Loops
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		// if(len) printf("%d: len=%d\n", i, len);
		if(len) ret = 1LL * ret * len % MOD;
	}
	for(int i = 1; i <= N; ++i) if(!val[i])
	{	// Arbitrarily Begin at a Cycle
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		if(len) ret = 1LL * ret * len % MOD;
		if(len) printf("%d: %d -> %d\n", i, len, ret);
	}
	/* for(int i = 1; i <= N; ++i) if(!graph[i]) // Sink Node
	{
		printf("%d: %d\n", i, final[i]);
		if(final[i] > 1) ret = 1LL * ret * final[i] % MOD;
	} */
	for(int i = 1; i <= N; ++i) if(!graph[i])
	{	// Source with Trees
		int go = dfs2(i); // Tree-DP
		if(go) ret = 1LL * ret * go % MOD;
		if(go > 1) printf("%d: go=%d\n", i, go);
	}
	printf("%d\n", ret);
	return 0;
}

// Subgraph:
// Cycle: Multiply `ret` by Cycle length
// Chain: Multiply `ret` by Chain length
// Rooted_Chain: Multiply `ret` by Subtree Size (location of empty node)
// Node:White - contains engineer, outdegree = 1
//	Black - empty, outdegree of zero.

/*
3
1 3
2 3
4 3
>> 4
2
1 3
3 4
>> 3
6
1 2
2 3
3 4
5 6
6 7
7 4
>> 7

*/


#include <cstdio>
#include <vector>
typedef std::vector<int> vin;
const int MAXN = 2E5+5;
const int MOD  = 1E9+7;
bool dual[MAXN]{ };
int final[MAXN]{ };
int graph[MAXN]{ }; // Single Child
bool  low[MAXN]{ };
int   val[MAXN]{ };
bool  vis[MAXN]{ };
int N, ret=1;

vin G[MAXN]{ };

int dfs(int cur)
{
	if(!graph[cur])		// Hit the Base of a Leaf
	{
		// return val[cur];
		final[cur] += val[cur];
		// dual[cur] = true;
		return 0;
	}
	G[graph[cur]].push_back(cur); // Reverse Graph
	if(vis[graph[cur]])
	{
		if(!graph[graph[cur]]) // Sink Node with Multiple Sources
		{
			final[graph[cur]] += val[cur];
			// dual[graph[cur]] = false;
		}
		return 0;	// Entering Old Loop (multiple roots) ->O<-
	}
	if(val[graph[cur]])	// Current Self-Loop -> Cycle
		return val[cur] - val[graph[cur]] + 1;
	val[graph[cur]] = val[cur] + 1;
	int res = dfs(graph[cur]);
	vis[graph[cur]] = true;
	return res;
}

int dfs2(int cur)
{
	int rkt = 1;
	for(auto nxt: G[cur])
		rkt += dfs2(nxt);
	return rkt;
}

int main()
{
	scanf("%d", &N);
	for(int i = 0; i < N; ++i)
	{
		int u, v;
		scanf(" %d%d", &u, &v);
		if(u == v) continue;
		graph[u] = v;
		low[v] = true;
	}
	N <<= 1;
	for(int i = 1; i <= N; ++i) if(!low[i]) // Root of Tree
	{	// Only Chains + Loops
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		// printf("len=%d\n", len);
		if(len) ret = 1LL * ret * len % MOD;
	}
	for(int i = 1; i <= N; ++i) if(!val[i])
	{	// Arbitrarily Begin at a Cycle
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		if(len) ret = 1LL * ret * len % MOD;
		// printf("%d: %d -> %d\n", i, len, ret);
	}
	/* for(int i = 1; i <= N; ++i) if(!graph[i]) // Sink Node
	{
		printf("%d: %d\n", i, final[i]);
		if(final[i] > 1) ret = 1LL * ret * final[i] % MOD;
	} */
	for(int i = 1; i <= N; ++i) if(!graph[i])
	{
		int go = dfs2(i); // Tree-DP
		if(go) ret = 1LL * ret * go % MOD;
	}
	printf("%d\n", ret);
	return 0;
}

// Subgraph:
// Cycle: Multiply `ret` by Cycle length
// Chain: Multiply `ret` by Chain length
// Rooted_Chain: Multiply `ret` by Sum of Chains

/*
3
1 3
2 3
4 3
>> 4
2
1 3
3 4
>> 3
6
1 2
2 3
3 4
5 6
6 7
7 4
*/


#include <cstdio>
#include <vector>
typedef std::vector<int> vin;
const int MAXN = 2E5+5;
const int MOD  = 1E9+7;
int final[MAXN]{ };
int graph[MAXN]{ }; // Single Child
bool  low[MAXN]{ };
int   val[MAXN]{ };
bool  vis[MAXN]{ };
int N, ret=1;

vin G[MAXN]{ };

int dfs(int cur)
{
	if(!graph[cur]) // Hit the Base of a Leaf
	{
		final[cur] += val[cur];
		return 1;
	}
	G[graph[cur]].push_back(cur); // Reverse Graph
	if(vis[graph[cur]])
	{
		if(!graph[graph[cur]]) // Sink Node with Multiple Sources
			final[graph[cur]] += val[cur];
		return 1;	// Entering Old Loop (multiple roots) ->O<-
	}
	if(val[graph[cur]])	// Current Self-Loop -> Cycle
		return (cur == graph[cur]) ? 1 : 2;	// Rotate Along Cycle
	val[graph[cur]] = val[cur] + 1;
	int res = dfs(graph[cur]);
	vis[graph[cur]] = true;
	return res;
}

int dfs2(int cur)
{
	int rkt = 1;
	for(auto nxt: G[cur])
		rkt += dfs2(nxt);
	return rkt;
}

int main()
{
	scanf("%d", &N);
	for(int i = 0; i < N; ++i)
	{
		int u, v;
		scanf(" %d%d", &u, &v);
		// Allow Self-Loops!
		graph[u] = v;
		low[v] = true;
	}
	N <<= 1;
	for(int i = 1; i <= N; ++i) if(!low[i]) // Root of Tree
	{	// Only Chains + Loops
		val[i] = 1;
		ret = 1LL * ret * dfs(i) % MOD;
		vis[i] = true;
	}
	for(int i = 1; i <= N; ++i) if(!val[i])
	{	// Arbitrarily Begin at a Cycle
		val[i] = 1;
		ret = 1LL * ret * dfs(i) % MOD;
		vis[i] = true;
	}
	for(int i = 1; i <= N; ++i) if(!graph[i])
		ret = 1LL * ret * dfs2(i) % MOD; // Source of Tree
	printf("%d\n", ret);
	return 0;
}


#include <cstdio>
const int MAXN = 2E5+5;
const int MOD  = 1E9+7;
int final[MAXN]{ };
int graph[MAXN]{ }; // Single Child
bool  low[MAXN]{ };
int   val[MAXN]{ };
bool  vis[MAXN]{ };
int N, ret=1;

int dfs(int cur)
{
	if(!graph[cur])		// Hit the Base of a Leaf
	{
		// return val[cur];
		final[cur] = (1LL * final[cur] + val[cur]) % MOD;
		return 0;
	}
	if(vis[graph[cur]])
	{
		if(!graph[graph[cur]]) // Sink Node with Multiple Sources
			final[graph[cur]] = (1LL * final[graph[cur]] + val[cur]) % MOD;
		return 0;	// Entering Old Loop (multiple roots) ->O<-
	}
	if(val[graph[cur]])	// Current Self-Loop
		return val[cur] - val[graph[cur]] + 1;
	val[graph[cur]] = val[cur] + 1;
	int res = dfs(graph[cur]);
	vis[graph[cur]] = true;
	return res;
}

int main()
{
	scanf("%d", &N);
	for(int i = 0; i < N; ++i)
	{
		int u, v;
		scanf(" %d%d", &u, &v);
		if(u == v) continue;
		graph[u] = v;
		low[v] = true;
	}
	N <<= 1;
	for(int i = 1; i <= N; ++i) if(!low[i]) // Root of Tree
	{	// Only Chains + Loops
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		// printf("len=%d\n", len);
		if(len) ret = 1LL * ret * len % MOD;
	}
	for(int i = 1; i <= N; ++i) if(!val[i])
	{	// Arbitrarily Begin at a Cycle
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		if(len) ret = 1LL * ret * len % MOD;
	}
	for(int i = 1; i <= N; ++i) if(!graph[i]) // Sink Node
	{
		// printf("%d: %d\n", i, final[i]);
		if(final[i]) ret = 1LL * ret * final[i] % MOD;
	}
	printf("%d\n", ret);
	return 0;
}

// Subgraph:
// Cycle: Multiply `ret` by Cycle length
// Chain: Multiply `ret` by Chain length
// Rooted_Chain: Multiply `ret` by Sum of Chains


#include <cstdio>
#include <vector>
typedef std::vector<int> vin;
const int MAXN = 2E5+5;
const int MOD  = 1E9+7;
bool dual[MAXN]{ };
int final[MAXN]{ };
int graph[MAXN]{ }; // Single Child
bool  low[MAXN]{ };
int   val[MAXN]{ };
bool  vis[MAXN]{ };
int N, ret=1;

vin G[MAXN]{ };

int dfs(int cur)
{
	if(!graph[cur]) // Hit the Base of a Leaf
	{
		// return val[cur];
		final[cur] += val[cur];
		// dual[cur] = true;
		return 0;
	}
	G[graph[cur]].push_back(cur); // Reverse Graph
	if(vis[graph[cur]])
	{
		if(!graph[graph[cur]]) // Sink Node with Multiple Sources
		{
			final[graph[cur]] += val[cur];
			// dual[graph[cur]] = false;
		}
		return 0;	// Entering Old Loop (multiple roots) ->O<-
	}
	if(val[graph[cur]])	// Current Self-Loop -> Cycle
		return (cur == graph[cur]) ? 1 : 2;	// Rotate Along Cycle
	val[graph[cur]] = val[cur] + 1;
	int res = dfs(graph[cur]);
	vis[graph[cur]] = true;
	return res;
}

int dfs2(int cur)
{
	int rkt = 1;
	for(auto nxt: G[cur])
		rkt += dfs2(nxt);
	return rkt;
}

int main()
{
	// freopen("in.in", "r", stdin);
	scanf("%d", &N);
	for(int i = 0; i < N; ++i)
	{
		int u, v;
		scanf(" %d%d", &u, &v);
		// if(u == v) continue; // Allow Self-Loops!
		graph[u] = v;
		low[v] = true;
	}
	N <<= 1;
	for(int i = 1; i <= N; ++i) if(!low[i]) // Root of Tree
	{	// Only Chains + Loops
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		// if(len) printf("%d: len=%d\n", i, len);
		if(len) ret = 1LL * ret * len % MOD;
	}
	for(int i = 1; i <= N; ++i) if(!val[i])
	{	// Arbitrarily Begin at a Cycle
		val[i] = 1;
		int len = dfs(i);
		vis[i] = true;
		if(len) ret = 1LL * ret * len % MOD;
		// if(len) printf("%d: %d -> %d\n", i, len, ret);
	}
	/* for(int i = 1; i <= N; ++i) if(!graph[i]) // Sink Node
	{
		printf("%d: %d\n", i, final[i]);
		if(final[i] > 1) ret = 1LL * ret * final[i] % MOD;
	} */
	for(int i = 1; i <= N; ++i) if(!graph[i])
	{	// Source with Trees
		int go = dfs2(i); // Tree-DP
		if(go) ret = 1LL * ret * go % MOD;
		// if(go > 1) printf("%d: go=%d\n", i, go);
	}
	printf("%d\n", ret);
	return 0;
}

// Subgraph:
// Cycle: Multiply `ret` by Cycle length
// Chain: Multiply `ret` by Chain length
// Rooted_Chain: Multiply `ret` by Subtree Size (location of empty node)
// Node:White - contains engineer, outdegree = 1
//	Black - empty, outdegree of zero.

/*
3
1 3
2 3
4 3
>> 4
2
1 3
3 4
>> 3
6
1 2
2 3
3 4
5 6
6 7
7 4
>> 7

*/


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<string, int> psi;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef multiset<int> MI;
typedef complex<double> PX;
#define pb push_back
#define xx first
#define yy second
#define FOR(i,a,b) for(int i=a;i<int(b);i++)
#define FORB(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define all(c) c.begin(),c.end()

const int mod = 1e9+7;
const int N = 2e5+5;
int adj[N], cyc[N], vis[N];
int num_cyc = 0;

ll mod_pow(int p) {
	if (p == 0) return 1LL;
	ll st = mod_pow(p/2);
	if (p&1) return ((st*st)%mod * 2) % mod;
	return st*st % mod;
}

int main() {
	ios::sync_with_stdio(0);
	int n; cin >> n;
	FOR(i,0,n) {
		int u, v;
		cin >> u >> v;
		adj[u] = v;
	}
	ll ans = 1;
	for (int i = 1, j = 1; i <= N; i++) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[j] = j;
		while (!S.empty()) {
			int v = S.top();
			S.pop();
			if (!adj[v]) break;
			if (vis[adj[v]]) {
				if (vis[adj[v]] == j) {
					if (v != adj[v]) ans = (ans * 2) % mod;
					int u = v;
					do {
						cyc[u] = true;
						u = adj[u];
					} while (u != v);
				}
				break;
			}
			vis[adj[v]] = j;
			S.push(adj[v]);
		}
		j++;
	}
	VVI G(N);
	FOR(i,1,N) if (adj[i]) {
		G[i].pb(adj[i]);
		G[adj[i]].pb(i);
	}
	memset(vis, 0, sizeof vis);
	FOR(i,1,N) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = true;
		int t = 0;
		while (!S.empty()) {
			int u = S.top();
			S.pop();
			if (cyc[u]) t = -1;
			if (t != -1) t++;
			for (int v : G[u]) if (!vis[v]) {
				vis[v] = true;
				S.push(v);
			}
		}
		if (t != -1) ans = (ans * t) % mod;
	}
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<string, int> psi;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef multiset<int> MI;
typedef complex<double> PX;
#define pb push_back
#define xx first
#define yy second
#define FOR(i,a,b) for(int i=a;i<int(b);i++)
#define FORB(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define all(c) c.begin(),c.end()

const int mod = 1e9+7;
const int N = 1e5+5;
int adj[N], cyc[N], vis[N];
int num_cyc = 0;

ll mod_pow(int p) {
	if (p == 0) return 1LL;
	ll st = mod_pow(p/2);
	if (p&1) return ((st*st)%mod * 2) % mod;
	return st*st % mod;
}

int main() {
	ios::sync_with_stdio(0);
	int n; cin >> n;
	FOR(i,0,n) {
		int u, v;
		cin >> u >> v;
		adj[u] = v;
	}
	ll ans = 1;
	for (int i = 1, j = 1; i <= N; i++) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[j] = true;
		while (!S.empty()) {
			int v = S.top();
			S.pop();
			if (!adj[v]) break;
			if (vis[adj[v]]) {
				if (vis[adj[v]] == j) {
					ans = (ans * 2) % mod;
					int u = v;
					do {
						cyc[u] = true;
						u = adj[u];
					} while (u != v);
				}
				break;
			}
			vis[adj[v]] = j;
			S.push(adj[v]);
		}
		j++;
	}
	VVI G(N);
	FOR(i,1,N) if (adj[i]) {
		G[i].pb(adj[i]);
		G[adj[i]].pb(i);
	}
	memset(vis, 0, sizeof vis);
	FOR(i,1,N) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = true;
		int t = 0;
		while (!S.empty()) {
			int u = S.top();
			S.pop();
			if (cyc[u]) t = -1;
			if (t != -1) t++;
			for (int v : G[u]) if (!vis[v]) {
				vis[v] = true;
				S.push(v);
			}
		}
		if (t != -1) ans = (ans * t) % mod;
	}
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<string, int> psi;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef multiset<int> MI;
typedef complex<double> PX;
#define pb push_back
#define xx first
#define yy second
#define FOR(i,a,b) for(int i=a;i<int(b);i++)
#define FORB(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define all(c) c.begin(),c.end()

const int mod = 1e9+7;
const int N = 2e5+5;
int adj[N], cyc[N], vis[N];
int num_cyc = 0;

ll mod_pow(int p) {
	if (p == 0) return 1LL;
	ll st = mod_pow(p/2);
	if (p&1) return ((st*st)%mod * 2) % mod;
	return st*st % mod;
}

int main() {
	ios::sync_with_stdio(0);
	int n; cin >> n;
	FOR(i,0,n) {
		int u, v;
		cin >> u >> v;
		adj[u] = v;
	}
	ll ans = 1;
	for (int i = 1, j = 1; i <= N; i++) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[j] = true;
		while (!S.empty()) {
			int v = S.top();
			S.pop();
			if (!adj[v]) break;
			if (vis[adj[v]]) {
				if (vis[adj[v]] == j) {
					if (v != adj[v]) ans = (ans * 2) % mod;
					int u = v;
					do {
						cyc[u] = true;
						u = adj[u];
					} while (u != v);
				}
				break;
			}
			vis[adj[v]] = j;
			S.push(adj[v]);
		}
		j++;
	}
	VVI G(N);
	FOR(i,1,N) if (adj[i]) {
		G[i].pb(adj[i]);
		G[adj[i]].pb(i);
	}
	memset(vis, 0, sizeof vis);
	FOR(i,1,N) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = true;
		int t = 0;
		while (!S.empty()) {
			int u = S.top();
			S.pop();
			if (cyc[u]) t = -1;
			if (t != -1) t++;
			for (int v : G[u]) if (!vis[v]) {
				vis[v] = true;
				S.push(v);
			}
		}
		if (t != -1) ans = (ans * t) % mod;
	}
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<string, int> psi;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef multiset<int> MI;
typedef complex<double> PX;
#define pb push_back
#define xx first
#define yy second
#define FOR(i,a,b) for(int i=a;i<int(b);i++)
#define FORB(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define all(c) c.begin(),c.end()

const int mod = 1e9+7;
const int N = 2e5+5;
int adj[N], cyc[N], vis[N];
int num_cyc = 0;

ll mod_pow(int p) {
	if (p == 0) return 1LL;
	ll st = mod_pow(p/2);
	if (p&1) return ((st*st)%mod * 2) % mod;
	return st*st % mod;
}

int main() {
	ios::sync_with_stdio(0);
	int n; cin >> n;
	FOR(i,0,n) {
		int u, v;
		cin >> u >> v;
		adj[u] = v;
	}
	ll ans = 1;
	for (int i = 1, j = 1; i <= N; i++) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[j] = true;
		while (!S.empty()) {
			int v = S.top();
			S.pop();
			if (!adj[v]) break;
			if (vis[adj[v]]) {
				if (vis[adj[v]] == j) {
					ans = (ans * 2) % mod;
					int u = v;
					do {
						cyc[u] = true;
						u = adj[u];
					} while (u != v);
				}
				break;
			}
			vis[adj[v]] = j;
			S.push(adj[v]);
		}
		j++;
	}
	VVI G(N);
	FOR(i,1,N) if (adj[i]) {
		G[i].pb(adj[i]);
		G[adj[i]].pb(i);
	}
	memset(vis, 0, sizeof vis);
	FOR(i,1,N) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = true;
		int t = 0;
		while (!S.empty()) {
			int u = S.top();
			S.pop();
			if (cyc[u]) t = -1;
			if (t != -1) t++;
			for (int v : G[u]) if (!vis[v]) {
				vis[v] = true;
				S.push(v);
			}
		}
		if (t != -1) ans = (ans * t) % mod;
	}
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<string, int> psi;
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<ll> VL;
typedef multiset<int> MI;
typedef complex<double> PX;
#define pb push_back
#define xx first
#define yy second
#define FOR(i,a,b) for(int i=a;i<int(b);i++)
#define FORB(i,a,b) for(int i=int(b)-1;i>=int(a);i--)
#define all(c) c.begin(),c.end()

const int mod = 1e9+7;
const int N = 2e5+5;
int adj[N], cyc[N], vis[N];
int num_cyc = 0;

ll mod_pow(int p) {
	if (p == 0) return 1LL;
	ll st = mod_pow(p/2);
	if (p&1) return ((st*st)%mod * 2) % mod;
	return st*st % mod;
}

int main() {
	ios::sync_with_stdio(0);
	int n; cin >> n;
	FOR(i,0,n) {
		int u, v;
		cin >> u >> v;
		adj[u] = v;
	}
	ll ans = 1;
	for (int i = 1, j = 1; i <= N; i++) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = j;
		while (!S.empty()) {
			int v = S.top();
			S.pop();
			if (!adj[v]) break;
			if (vis[adj[v]]) {
				if (vis[adj[v]] == j) {
					if (v != adj[v]) ans = (ans * 2) % mod;
					int u = v;
					do {
						cyc[u] = true;
						u = adj[u];
					} while (u != v);
				}
				break;
			}
			vis[adj[v]] = j;
			S.push(adj[v]);
		}
		j++;
	}
	VVI G(N);
	FOR(i,1,N) if (adj[i]) {
		G[i].pb(adj[i]);
		G[adj[i]].pb(i);
	}
	memset(vis, 0, sizeof vis);
	FOR(i,1,N) if (!vis[i] && adj[i]) {
		stack<int> S;
		S.push(i);
		vis[i] = true;
		int t = 0;
		while (!S.empty()) {
			int u = S.top();
			S.pop();
			if (cyc[u]) t = -1;
			if (t != -1) t++;
			for (int v : G[u]) if (!vis[v]) {
				vis[v] = true;
				S.push(v);
			}
		}
		if (t != -1) ans = (ans * t) % mod;
	}
	cout << ans << endl;
	return 0;
}


#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

stringstream output;

/** Actually outputs the result and end the program.*/
inline void eOP();

#include <unordered_map>
#include <unordered_set>

#ifndef MOD_H_INCLUDED
#define MOD_H_INCLUDED

#ifndef ALGORITHM_H_INCLUDED
#define ALGORITHM_H_INCLUDED

#include <algorithm>

using namespace std;

#define gcf gcd
#define gcd euclideanAlgorithm

template <typename N>
inline N euclideanAlgorithm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y);

template <typename N>
inline N lcm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b)
{
	while (a != N(0))
	{
        b %= a;
        swap(a, b);
	}
	return b;
}

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y)
{
    // Do euclidean algorithm on
    // (a, b), (1, 0), (0, 1)

    N l[3] = {a, 1, 0};
    N r[3] = {b, 0, 1};

    while (l[0] != 0)
    {
    	N n = r[0] / l[0];
    	for (int i = 0; i < 3; ++i)
		{
            r[i] -= l[i] * n;
            swap(l[i], r[i]);
		}
    }

    x = r[1];
    y = r[2];
    return r[0];
}

template <typename N>
inline N lcm(N a, N b)
{
    return a / gcd(a, b) * b;
}

#endif // ALGORITHM_H_INCLUDED
#ifndef RELOP_H_INCLUDED
#define RELOP_H_INCLUDED

/*
Just write

inline R operator -(K a);
inline bool operator <(K a, S b);
inline bool operator ==(K a, S b);
inline R operator ~(K a);
inline R& operator +=(K& a, S b);
inline R& operator *=(K& a, S b);
inline R& operator /=(K& a, S b);
inline R& operator &=(K& a, S b);
inline R& operator |=(K& a, S b);
inline R& operator <<=(K& a, S b);
inline ostream& operator<<(ostream& os, const K& a);
inline istream& operator>>(istream& is, K& a);

*/
// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b);
template <typename T>
inline T operator -(const T& a, const T& b);
template <typename T>
inline T operator +(const T& a);
template <typename T>
inline T operator *(const T& a, const T& b);
template <typename T>
inline T operator /(const T& a, const T& b);
template <typename T>
inline T operator %(const T& a, const T& b);
template <typename T>
inline T& operator ++(T& a);
template <typename T>
inline T operator ++(T& a, int);
template <typename T>
inline T& operator --(T& a);
template <typename T>
inline T operator --(T& a, int);

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b);
template <typename T>
inline bool operator>(const T& a,const T& b);
template <typename T>
inline bool operator<=(const T& a,const T& b);
template <typename T>
inline bool operator>=(const T& a,const T& b);

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b);
template <typename T>
inline T operator |(const T& a, const T& b);
template <typename T>
inline T operator ^(const T& a, const T& b);
template <typename T>
inline T operator <<(const T& a, const T& b);
template <typename T>
inline T operator >>(const T& a, const T& b);

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b);
template <typename T>
inline T& operator %=(T& a, const T& b);
template <typename T>
inline T& operator ^=(T& a, const T& b);
template <typename T>
inline T& operator >>=(T& a, const T& b);

// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b)
{
	T result = a;
	return result += b;
}

template <typename T>
inline T operator -(const T& a, const T& b)
{
	T result = a;
	return result -= b;
}

template <typename T>
inline T operator +(const T& a)
{
	return a;
}

template <typename T>
inline T operator *(const T& a, const T& b)
{
	T result = a;
	return result *= b;
}

template <typename T>
inline T operator /(const T& a, const T& b)
{
	T result = a;
	return result /= b;
}

template <typename T>
inline T operator %(const T& a, const T& b)
{
	T result = a;
	return result %= b;
}

template <typename T>
inline T& operator ++(T& a)
{
	return a += 1;
}

template <typename T>
inline T operator ++(T& a, int)
{
	T result = a;
	++a;
	return result;
}

template <typename T>
inline T& operator --(T& a)
{
	return a -= 1;
}

template <typename T>
inline T operator --(T& a, int)
{
	T result = a;
	--a;
	return result;
}

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b)
{
	return !(a == b);
}

template <typename T>
inline bool operator>(const T& a,const T& b)
{
	return b < a;
}

template <typename T>
inline bool operator<=(const T& a,const T& b)
{
	return !(a > b);
}

template <typename T>
inline bool operator>=(const T& a,const T& b)
{
	return !(a < b);
}

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b)
{
	T result = a;
	return result &= b;
}

template <typename T>
inline T operator |(const T& a, const T& b)
{
	T result = a;
	return result |= b;
}

template <typename T>
inline T operator ^(const T& a, const T& b)
{
	T result = a;
	return result ^= b;
}

template <typename T>
inline T operator <<(const T& a, const T& b)
{
	T result = a;
	return result <<= b;
}

template <typename T>
inline T operator >>(const T& a, const T& b)
{
	T result = a;
	return result >>= b;
}

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b)
{
	return a += -b;
}

template <typename T>
inline T& operator %=(T& a, const T& b)
{
	return a -= a / b * b;
}

template <typename T>
inline T& operator ^=(T& a, const T& b)
{
	return a = ~(a & b) & (a | b);
}

template <typename T>
inline T& operator >>=(T& a, const T& b)
{
	return a <<= -b;
}

#endif // RELOP_H_INCLUDED

#ifndef MOD
#define MOD 1000000007
#endif // MOD

class Remainder
{
public:
    long long value;
    Remainder(long long = 0);
};

inline Remainder operator + (const Remainder & l, const Remainder & r);

inline Remainder operator - (const Remainder & l, const Remainder & r);

inline Remainder operator * (const Remainder & l, const Remainder & r);

inline Remainder operator / (const Remainder & l, const Remainder & r);

inline Remainder & operator++(Remainder & r);

inline Remainder operator++(Remainder & r, int);

inline Remainder & operator--(Remainder & r);

inline Remainder operator--(Remainder & r, int);

inline Remainder operator + (const Remainder & r);

inline Remainder operator - (const Remainder & r);

inline Remainder & operator += (Remainder & l, const Remainder & r);

inline Remainder & operator -= (Remainder & l, const Remainder & r);

inline Remainder & operator *= (Remainder & l, const Remainder & r);

inline Remainder & operator /= (Remainder & l, const Remainder & r);

inline Remainder operator ~ (const Remainder & l);

inline bool operator == (const Remainder & l, const Remainder & r);

inline bool operator < (const Remainder & l, const Remainder & r);

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o);

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o);

inline Remainder::Remainder(long long r)
{
    value = r;
	value %= MOD;
	if (value < 0)
	{
		value += MOD;
	}
}

inline Remainder operator + (const Remainder & l, const Remainder & r) // A + B
{
   Remainder oResult(l.value + r.value);
   return oResult ;
}

inline Remainder operator - (const Remainder & l, const Remainder & r) // A - B
{
   Remainder oResult(l.value - r.value);
   return oResult ;
}

inline Remainder operator * (const Remainder & l, const Remainder & r) // A * B
{
   Remainder oResult(l.value * r.value);
   return oResult ;
}

inline Remainder operator / (const Remainder & l, const Remainder & r) // A / B
{
	long long x, y;
	gcd(r.value, static_cast<long long>(MOD), x, y);
   Remainder oResult(l * x);
   return oResult ;
}

inline Remainder & operator++(Remainder & r) // ++A
{
   r += 1;
   return r ;
}

inline Remainder operator++(Remainder & r, int) // A++
{
   Remainder oCopy(r);
   r += 1;
   return oCopy ;
}

inline Remainder & operator--(Remainder & r) // --A
{
   r -= 1;
   return r ;
}

inline Remainder operator--(Remainder & r, int) // A--
{
   Remainder oCopy(r);
   r -= 1;
   return oCopy ;
}

inline Remainder operator + (const Remainder & r) // +A
{
   return r ;
}

inline Remainder operator - (const Remainder & r) // -A
{
	Remainder temp(-(r.value));
   return temp;
}

inline Remainder & operator += (Remainder & l, const Remainder & r) // A += B
{
   l = l + r;

   return l ;
}

inline Remainder & operator -= (Remainder & l, const Remainder & r) // A -= B
{
   l = l - r;

   return l ;
}

inline Remainder & operator *= (Remainder & l, const Remainder & r) // A *= B
{
   l = l * r;

   return l ;
}

inline Remainder & operator /= (Remainder & l, const Remainder & r) // A /= B
{
   l = l / r;

   return l ;
}

inline Remainder operator ~ (const Remainder & l) // ~A
{
   Remainder oResult(-l);
   return oResult ;
}

inline bool operator == (const Remainder & l, const Remainder & r) // A == B
{
   return l.value == r.value ;
}

inline bool operator < (const Remainder & l, const Remainder & r) // A < B
{
   return l.value < r.value ;
}

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o)
{
   os << o.value;
   return os ;
}

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o)
{
   is >> o.value;
   o = Remainder(o);
   return is ;
}

#endif // MOD_H_INCLUDED

#include <vector>
#include <cstdio>

int main()
{
	int n;
	scanf("%d", &n);

	int* s = new int[n];
	unordered_map<int,int> f;
	unordered_map<int,vector<int>> b;
	rep (i, n)
	{
		int from, to;
		scanf("%d%d", &from, &to);
		s[i] = from;
		f[from] = to;
		b[to].push_back(from);
	}

	Remainder result = 1;

    unordered_set<int> considered;
    rep (i, n)
    {
        int spot = s[i];
        if (considered.count(spot))
		{
            continue;
		}

        while (f.find(spot) != f.end())
		{
            spot = f[spot];
            if (spot == s[i])
			{
                break;
			}
		}

		if (spot == s[i])
		{
            if (spot != f[spot])
			{
                result *= 2;
			}

			while (f.find(spot) != f.end())
			{
				spot = f[spot];
				considered.insert(spot);
				if (spot == s[i])
				{
					break;
				}
			}

            continue;
		}

		vector<int> togo;
		togo.push_back(spot);

		int spots = 0;
		bool loop = false;

		int index = 0;

		while (index != togo.size())
		{
			++spots;
			int spot = togo[index];
			++index;
            considered.insert(spot);

            int bindex = 0;
            while (bindex != b[spot].size())
			{
                togo.push_back(b[spot][bindex]);
                ++bindex;
			}
		}

		result *= spots;
    }

	cout << result;

	eOP();
}

inline void eOP()
{
	cout << output.str();
	output.str(string());
	exit(0);
}


#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

stringstream output;

/** Actually outputs the result and end the program.*/
inline void eOP();

#include <unordered_map>
#include <unordered_set>

#ifndef MOD_H_INCLUDED
#define MOD_H_INCLUDED

#ifndef ALGORITHM_H_INCLUDED
#define ALGORITHM_H_INCLUDED

#include <algorithm>

using namespace std;

#define gcf gcd
#define gcd euclideanAlgorithm

template <typename N>
inline N euclideanAlgorithm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y);

template <typename N>
inline N lcm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b)
{
	while (a != N(0))
	{
        b %= a;
        swap(a, b);
	}
	return b;
}

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y)
{
    // Do euclidean algorithm on
    // (a, b), (1, 0), (0, 1)

    N l[3] = {a, 1, 0};
    N r[3] = {b, 0, 1};

    while (l[0] != 0)
    {
    	N n = r[0] / l[0];
    	for (int i = 0; i < 3; ++i)
		{
            r[i] -= l[i] * n;
            swap(l[i], r[i]);
		}
    }

    x = r[1];
    y = r[2];
    return r[0];
}

template <typename N>
inline N lcm(N a, N b)
{
    return a / gcd(a, b) * b;
}

#endif // ALGORITHM_H_INCLUDED
#ifndef RELOP_H_INCLUDED
#define RELOP_H_INCLUDED

/*
Just write

inline R operator -(K a);
inline bool operator <(K a, S b);
inline bool operator ==(K a, S b);
inline R operator ~(K a);
inline R& operator +=(K& a, S b);
inline R& operator *=(K& a, S b);
inline R& operator /=(K& a, S b);
inline R& operator &=(K& a, S b);
inline R& operator |=(K& a, S b);
inline R& operator <<=(K& a, S b);
inline ostream& operator<<(ostream& os, const K& a);
inline istream& operator>>(istream& is, K& a);

*/
// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b);
template <typename T>
inline T operator -(const T& a, const T& b);
template <typename T>
inline T operator +(const T& a);
template <typename T>
inline T operator *(const T& a, const T& b);
template <typename T>
inline T operator /(const T& a, const T& b);
template <typename T>
inline T operator %(const T& a, const T& b);
template <typename T>
inline T& operator ++(T& a);
template <typename T>
inline T operator ++(T& a, int);
template <typename T>
inline T& operator --(T& a);
template <typename T>
inline T operator --(T& a, int);

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b);
template <typename T>
inline bool operator>(const T& a,const T& b);
template <typename T>
inline bool operator<=(const T& a,const T& b);
template <typename T>
inline bool operator>=(const T& a,const T& b);

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b);
template <typename T>
inline T operator |(const T& a, const T& b);
template <typename T>
inline T operator ^(const T& a, const T& b);
template <typename T>
inline T operator <<(const T& a, const T& b);
template <typename T>
inline T operator >>(const T& a, const T& b);

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b);
template <typename T>
inline T& operator %=(T& a, const T& b);
template <typename T>
inline T& operator ^=(T& a, const T& b);
template <typename T>
inline T& operator >>=(T& a, const T& b);

// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b)
{
	T result = a;
	return result += b;
}

template <typename T>
inline T operator -(const T& a, const T& b)
{
	T result = a;
	return result -= b;
}

template <typename T>
inline T operator +(const T& a)
{
	return a;
}

template <typename T>
inline T operator *(const T& a, const T& b)
{
	T result = a;
	return result *= b;
}

template <typename T>
inline T operator /(const T& a, const T& b)
{
	T result = a;
	return result /= b;
}

template <typename T>
inline T operator %(const T& a, const T& b)
{
	T result = a;
	return result %= b;
}

template <typename T>
inline T& operator ++(T& a)
{
	return a += 1;
}

template <typename T>
inline T operator ++(T& a, int)
{
	T result = a;
	++a;
	return result;
}

template <typename T>
inline T& operator --(T& a)
{
	return a -= 1;
}

template <typename T>
inline T operator --(T& a, int)
{
	T result = a;
	--a;
	return result;
}

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b)
{
	return !(a == b);
}

template <typename T>
inline bool operator>(const T& a,const T& b)
{
	return b < a;
}

template <typename T>
inline bool operator<=(const T& a,const T& b)
{
	return !(a > b);
}

template <typename T>
inline bool operator>=(const T& a,const T& b)
{
	return !(a < b);
}

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b)
{
	T result = a;
	return result &= b;
}

template <typename T>
inline T operator |(const T& a, const T& b)
{
	T result = a;
	return result |= b;
}

template <typename T>
inline T operator ^(const T& a, const T& b)
{
	T result = a;
	return result ^= b;
}

template <typename T>
inline T operator <<(const T& a, const T& b)
{
	T result = a;
	return result <<= b;
}

template <typename T>
inline T operator >>(const T& a, const T& b)
{
	T result = a;
	return result >>= b;
}

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b)
{
	return a += -b;
}

template <typename T>
inline T& operator %=(T& a, const T& b)
{
	return a -= a / b * b;
}

template <typename T>
inline T& operator ^=(T& a, const T& b)
{
	return a = ~(a & b) & (a | b);
}

template <typename T>
inline T& operator >>=(T& a, const T& b)
{
	return a <<= -b;
}

#endif // RELOP_H_INCLUDED

#ifndef MOD
#define MOD 1000000007
#endif // MOD

class Remainder
{
public:
    long long value;
    Remainder(long long = 0);
};

inline Remainder operator + (const Remainder & l, const Remainder & r);

inline Remainder operator - (const Remainder & l, const Remainder & r);

inline Remainder operator * (const Remainder & l, const Remainder & r);

inline Remainder operator / (const Remainder & l, const Remainder & r);

inline Remainder & operator++(Remainder & r);

inline Remainder operator++(Remainder & r, int);

inline Remainder & operator--(Remainder & r);

inline Remainder operator--(Remainder & r, int);

inline Remainder operator + (const Remainder & r);

inline Remainder operator - (const Remainder & r);

inline Remainder & operator += (Remainder & l, const Remainder & r);

inline Remainder & operator -= (Remainder & l, const Remainder & r);

inline Remainder & operator *= (Remainder & l, const Remainder & r);

inline Remainder & operator /= (Remainder & l, const Remainder & r);

inline Remainder operator ~ (const Remainder & l);

inline bool operator == (const Remainder & l, const Remainder & r);

inline bool operator < (const Remainder & l, const Remainder & r);

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o);

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o);

inline Remainder::Remainder(long long r)
{
    value = r;
	value %= MOD;
	if (value < 0)
	{
		value += MOD;
	}
}

inline Remainder operator + (const Remainder & l, const Remainder & r) // A + B
{
   Remainder oResult(l.value + r.value);
   return oResult ;
}

inline Remainder operator - (const Remainder & l, const Remainder & r) // A - B
{
   Remainder oResult(l.value - r.value);
   return oResult ;
}

inline Remainder operator * (const Remainder & l, const Remainder & r) // A * B
{
   Remainder oResult(l.value * r.value);
   return oResult ;
}

inline Remainder operator / (const Remainder & l, const Remainder & r) // A / B
{
	long long x, y;
	gcd(r.value, static_cast<long long>(MOD), x, y);
   Remainder oResult(l * x);
   return oResult ;
}

inline Remainder & operator++(Remainder & r) // ++A
{
   r += 1;
   return r ;
}

inline Remainder operator++(Remainder & r, int) // A++
{
   Remainder oCopy(r);
   r += 1;
   return oCopy ;
}

inline Remainder & operator--(Remainder & r) // --A
{
   r -= 1;
   return r ;
}

inline Remainder operator--(Remainder & r, int) // A--
{
   Remainder oCopy(r);
   r -= 1;
   return oCopy ;
}

inline Remainder operator + (const Remainder & r) // +A
{
   return r ;
}

inline Remainder operator - (const Remainder & r) // -A
{
	Remainder temp(-(r.value));
   return temp;
}

inline Remainder & operator += (Remainder & l, const Remainder & r) // A += B
{
   l = l + r;

   return l ;
}

inline Remainder & operator -= (Remainder & l, const Remainder & r) // A -= B
{
   l = l - r;

   return l ;
}

inline Remainder & operator *= (Remainder & l, const Remainder & r) // A *= B
{
   l = l * r;

   return l ;
}

inline Remainder & operator /= (Remainder & l, const Remainder & r) // A /= B
{
   l = l / r;

   return l ;
}

inline Remainder operator ~ (const Remainder & l) // ~A
{
   Remainder oResult(-l);
   return oResult ;
}

inline bool operator == (const Remainder & l, const Remainder & r) // A == B
{
   return l.value == r.value ;
}

inline bool operator < (const Remainder & l, const Remainder & r) // A < B
{
   return l.value < r.value ;
}

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o)
{
   os << o.value;
   return os ;
}

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o)
{
   is >> o.value;
   o = Remainder(o);
   return is ;
}

#endif // MOD_H_INCLUDED

#include <vector>
#include <cstdio>

int main()
{
	int n;
	scanf("%d", &n);

	int* s = new int[n];
	unordered_map<int,int> f;
	unordered_map<int,vector<int>> b;
	rep (i, n)
	{
		int from, to;
		scanf("%d%d", &from, &to);
		s[i] = from;
		f[from] = to;
		b[to].push_back(from);
	}

	Remainder result = 1;

    unordered_set<int> considered;
    rep (i, n)
    {
    	int start = s[i];
        int spot = s[i];
        if (considered.count(spot))
		{
            continue;
		}

		unordered_set<int> visited;
		bool loop = false;
        while (f.find(spot) != f.end())
		{
			visited.insert(spot);
            spot = f[spot];
            if (visited.count(spot) || considered.count(spot))
			{
				loop = true;
                break;
			}
		}

		if (considered.count(spot))
		{
			continue;
		}

		if (loop)
		{
			spot = start;
			unordered_set<int> visited;
			while (f.find(spot) != f.end())
			{
				considered.insert(spot);
				visited.insert(spot);
				spot = f[spot];
				if (visited.count(spot))
				{
					break;
				}
			}

			if (spot != f[spot])
			{
                result *= 2;
			}

		}

		vector<int> togo;
		togo.push_back(spot);

		int spots = 0;

		int index = 0;

		while (index != togo.size())
		{
			++spots;
			int spot = togo[index];
			++index;
            considered.insert(spot);

            int bindex = 0;
            while (bindex != b[spot].size())
			{
				int to = b[spot][bindex];
				if (!considered.count(to))
                {
                	togo.push_back(b[spot][bindex]);
                }
                ++bindex;
			}
		}

		if (!loop)
		{
			result *= spots;
		}
    }

	cout << result;

	eOP();
}

inline void eOP()
{
	cout << output.str();
	output.str(string());
	exit(0);
}


#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

stringstream output;

/** Actually outputs the result and end the program.*/
inline void eOP();

#include <unordered_map>
#include <unordered_set>

#ifndef MOD_H_INCLUDED
#define MOD_H_INCLUDED

#ifndef ALGORITHM_H_INCLUDED
#define ALGORITHM_H_INCLUDED

#include <algorithm>

using namespace std;

#define gcf gcd
#define gcd euclideanAlgorithm

template <typename N>
inline N euclideanAlgorithm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y);

template <typename N>
inline N lcm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b)
{
	while (a != N(0))
	{
        b %= a;
        swap(a, b);
	}
	return b;
}

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y)
{
    // Do euclidean algorithm on
    // (a, b), (1, 0), (0, 1)

    N l[3] = {a, 1, 0};
    N r[3] = {b, 0, 1};

    while (l[0] != 0)
    {
    	N n = r[0] / l[0];
    	for (int i = 0; i < 3; ++i)
		{
            r[i] -= l[i] * n;
            swap(l[i], r[i]);
		}
    }

    x = r[1];
    y = r[2];
    return r[0];
}

template <typename N>
inline N lcm(N a, N b)
{
    return a / gcd(a, b) * b;
}

#endif // ALGORITHM_H_INCLUDED
#ifndef RELOP_H_INCLUDED
#define RELOP_H_INCLUDED

/*
Just write

inline R operator -(K a);
inline bool operator <(K a, S b);
inline bool operator ==(K a, S b);
inline R operator ~(K a);
inline R& operator +=(K& a, S b);
inline R& operator *=(K& a, S b);
inline R& operator /=(K& a, S b);
inline R& operator &=(K& a, S b);
inline R& operator |=(K& a, S b);
inline R& operator <<=(K& a, S b);
inline ostream& operator<<(ostream& os, const K& a);
inline istream& operator>>(istream& is, K& a);

*/
// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b);
template <typename T>
inline T operator -(const T& a, const T& b);
template <typename T>
inline T operator +(const T& a);
template <typename T>
inline T operator *(const T& a, const T& b);
template <typename T>
inline T operator /(const T& a, const T& b);
template <typename T>
inline T operator %(const T& a, const T& b);
template <typename T>
inline T& operator ++(T& a);
template <typename T>
inline T operator ++(T& a, int);
template <typename T>
inline T& operator --(T& a);
template <typename T>
inline T operator --(T& a, int);

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b);
template <typename T>
inline bool operator>(const T& a,const T& b);
template <typename T>
inline bool operator<=(const T& a,const T& b);
template <typename T>
inline bool operator>=(const T& a,const T& b);

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b);
template <typename T>
inline T operator |(const T& a, const T& b);
template <typename T>
inline T operator ^(const T& a, const T& b);
template <typename T>
inline T operator <<(const T& a, const T& b);
template <typename T>
inline T operator >>(const T& a, const T& b);

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b);
template <typename T>
inline T& operator %=(T& a, const T& b);
template <typename T>
inline T& operator ^=(T& a, const T& b);
template <typename T>
inline T& operator >>=(T& a, const T& b);

// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b)
{
	T result = a;
	return result += b;
}

template <typename T>
inline T operator -(const T& a, const T& b)
{
	T result = a;
	return result -= b;
}

template <typename T>
inline T operator +(const T& a)
{
	return a;
}

template <typename T>
inline T operator *(const T& a, const T& b)
{
	T result = a;
	return result *= b;
}

template <typename T>
inline T operator /(const T& a, const T& b)
{
	T result = a;
	return result /= b;
}

template <typename T>
inline T operator %(const T& a, const T& b)
{
	T result = a;
	return result %= b;
}

template <typename T>
inline T& operator ++(T& a)
{
	return a += 1;
}

template <typename T>
inline T operator ++(T& a, int)
{
	T result = a;
	++a;
	return result;
}

template <typename T>
inline T& operator --(T& a)
{
	return a -= 1;
}

template <typename T>
inline T operator --(T& a, int)
{
	T result = a;
	--a;
	return result;
}

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b)
{
	return !(a == b);
}

template <typename T>
inline bool operator>(const T& a,const T& b)
{
	return b < a;
}

template <typename T>
inline bool operator<=(const T& a,const T& b)
{
	return !(a > b);
}

template <typename T>
inline bool operator>=(const T& a,const T& b)
{
	return !(a < b);
}

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b)
{
	T result = a;
	return result &= b;
}

template <typename T>
inline T operator |(const T& a, const T& b)
{
	T result = a;
	return result |= b;
}

template <typename T>
inline T operator ^(const T& a, const T& b)
{
	T result = a;
	return result ^= b;
}

template <typename T>
inline T operator <<(const T& a, const T& b)
{
	T result = a;
	return result <<= b;
}

template <typename T>
inline T operator >>(const T& a, const T& b)
{
	T result = a;
	return result >>= b;
}

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b)
{
	return a += -b;
}

template <typename T>
inline T& operator %=(T& a, const T& b)
{
	return a -= a / b * b;
}

template <typename T>
inline T& operator ^=(T& a, const T& b)
{
	return a = ~(a & b) & (a | b);
}

template <typename T>
inline T& operator >>=(T& a, const T& b)
{
	return a <<= -b;
}

#endif // RELOP_H_INCLUDED

#ifndef MOD
#define MOD 1000000007
#endif // MOD

class Remainder
{
public:
    long long value;
    Remainder(long long = 0);
};

inline Remainder operator + (const Remainder & l, const Remainder & r);

inline Remainder operator - (const Remainder & l, const Remainder & r);

inline Remainder operator * (const Remainder & l, const Remainder & r);

inline Remainder operator / (const Remainder & l, const Remainder & r);

inline Remainder & operator++(Remainder & r);

inline Remainder operator++(Remainder & r, int);

inline Remainder & operator--(Remainder & r);

inline Remainder operator--(Remainder & r, int);

inline Remainder operator + (const Remainder & r);

inline Remainder operator - (const Remainder & r);

inline Remainder & operator += (Remainder & l, const Remainder & r);

inline Remainder & operator -= (Remainder & l, const Remainder & r);

inline Remainder & operator *= (Remainder & l, const Remainder & r);

inline Remainder & operator /= (Remainder & l, const Remainder & r);

inline Remainder operator ~ (const Remainder & l);

inline bool operator == (const Remainder & l, const Remainder & r);

inline bool operator < (const Remainder & l, const Remainder & r);

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o);

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o);

inline Remainder::Remainder(long long r)
{
    value = r;
	value %= MOD;
	if (value < 0)
	{
		value += MOD;
	}
}

inline Remainder operator + (const Remainder & l, const Remainder & r) // A + B
{
   Remainder oResult(l.value + r.value);
   return oResult ;
}

inline Remainder operator - (const Remainder & l, const Remainder & r) // A - B
{
   Remainder oResult(l.value - r.value);
   return oResult ;
}

inline Remainder operator * (const Remainder & l, const Remainder & r) // A * B
{
   Remainder oResult(l.value * r.value);
   return oResult ;
}

inline Remainder operator / (const Remainder & l, const Remainder & r) // A / B
{
	long long x, y;
	gcd(r.value, static_cast<long long>(MOD), x, y);
   Remainder oResult(l * x);
   return oResult ;
}

inline Remainder & operator++(Remainder & r) // ++A
{
   r += 1;
   return r ;
}

inline Remainder operator++(Remainder & r, int) // A++
{
   Remainder oCopy(r);
   r += 1;
   return oCopy ;
}

inline Remainder & operator--(Remainder & r) // --A
{
   r -= 1;
   return r ;
}

inline Remainder operator--(Remainder & r, int) // A--
{
   Remainder oCopy(r);
   r -= 1;
   return oCopy ;
}

inline Remainder operator + (const Remainder & r) // +A
{
   return r ;
}

inline Remainder operator - (const Remainder & r) // -A
{
	Remainder temp(-(r.value));
   return temp;
}

inline Remainder & operator += (Remainder & l, const Remainder & r) // A += B
{
   l = l + r;

   return l ;
}

inline Remainder & operator -= (Remainder & l, const Remainder & r) // A -= B
{
   l = l - r;

   return l ;
}

inline Remainder & operator *= (Remainder & l, const Remainder & r) // A *= B
{
   l = l * r;

   return l ;
}

inline Remainder & operator /= (Remainder & l, const Remainder & r) // A /= B
{
   l = l / r;

   return l ;
}

inline Remainder operator ~ (const Remainder & l) // ~A
{
   Remainder oResult(-l);
   return oResult ;
}

inline bool operator == (const Remainder & l, const Remainder & r) // A == B
{
   return l.value == r.value ;
}

inline bool operator < (const Remainder & l, const Remainder & r) // A < B
{
   return l.value < r.value ;
}

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o)
{
   os << o.value;
   return os ;
}

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o)
{
   is >> o.value;
   o = Remainder(o);
   return is ;
}

#endif // MOD_H_INCLUDED

#include <vector>
#include <cstdio>

int main()
{
	int n;
	scanf("%d", &n);

	int* s = new int[n];
	unordered_map<int,int> f;
	unordered_map<int,vector<int>> b;
	rep (i, n)
	{
		int from, to;
		scanf("%d%d", &from, &to);
		s[i] = from;
		f[from] = to;
		b[to].push_back(from);
	}

	Remainder result = 1;

    unordered_set<int> considered;
    rep (i, n)
    {
        int spot = s[i];
        if (considered.count(spot))
		{
            continue;
		}

		unordered_set<int> visited;
		bool loop = false;
        while (f.find(spot) != f.end())
		{
			visited.insert(spot);
            spot = f[spot];
            if (visited.count(spot))
			{
				loop = true;
                break;
			}
		}

		if (loop)
		{
			unordered_set<int> visited;
			while (f.find(spot) != f.end())
			{
				considered.insert(spot);
				visited.insert(spot);
				spot = f[spot];
				if (visited.count(spot))
				{
					break;
				}
			}

			if (spot != f[spot])
			{
                result *= 2;
			}

            continue;
		}

		vector<int> togo;
		togo.push_back(spot);

		int spots = 0;

		int index = 0;

		while (index != togo.size())
		{
			++spots;
			int spot = togo[index];
			++index;
            considered.insert(spot);

            int bindex = 0;
            while (bindex != b[spot].size())
			{
                togo.push_back(b[spot][bindex]);
                ++bindex;
			}
		}

		result *= spots;
    }

	cout << result;

	eOP();
}

inline void eOP()
{
	cout << output.str();
	output.str(string());
	exit(0);
}


#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

#define rep(i, n) for(int i = 0; i < n; i++)

stringstream output;

/** Actually outputs the result and end the program.*/
inline void eOP();

#include <unordered_map>
#include <unordered_set>

#ifndef MOD_H_INCLUDED
#define MOD_H_INCLUDED

#ifndef ALGORITHM_H_INCLUDED
#define ALGORITHM_H_INCLUDED

#include <algorithm>

using namespace std;

#define gcf gcd
#define gcd euclideanAlgorithm

template <typename N>
inline N euclideanAlgorithm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y);

template <typename N>
inline N lcm(N a, N b);

template <typename N>
inline N euclideanAlgorithm(N a, N b)
{
	while (a != N(0))
	{
        b %= a;
        swap(a, b);
	}
	return b;
}

template <typename N>
inline N euclideanAlgorithm(N a, N b, N& x, N& y)
{
    // Do euclidean algorithm on
    // (a, b), (1, 0), (0, 1)

    N l[3] = {a, 1, 0};
    N r[3] = {b, 0, 1};

    while (l[0] != 0)
    {
    	N n = r[0] / l[0];
    	for (int i = 0; i < 3; ++i)
		{
            r[i] -= l[i] * n;
            swap(l[i], r[i]);
		}
    }

    x = r[1];
    y = r[2];
    return r[0];
}

template <typename N>
inline N lcm(N a, N b)
{
    return a / gcd(a, b) * b;
}

#endif // ALGORITHM_H_INCLUDED
#ifndef RELOP_H_INCLUDED
#define RELOP_H_INCLUDED

/*
Just write

inline R operator -(K a);
inline bool operator <(K a, S b);
inline bool operator ==(K a, S b);
inline R operator ~(K a);
inline R& operator +=(K& a, S b);
inline R& operator *=(K& a, S b);
inline R& operator /=(K& a, S b);
inline R& operator &=(K& a, S b);
inline R& operator |=(K& a, S b);
inline R& operator <<=(K& a, S b);
inline ostream& operator<<(ostream& os, const K& a);
inline istream& operator>>(istream& is, K& a);

*/
// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b);
template <typename T>
inline T operator -(const T& a, const T& b);
template <typename T>
inline T operator +(const T& a);
template <typename T>
inline T operator *(const T& a, const T& b);
template <typename T>
inline T operator /(const T& a, const T& b);
template <typename T>
inline T operator %(const T& a, const T& b);
template <typename T>
inline T& operator ++(T& a);
template <typename T>
inline T operator ++(T& a, int);
template <typename T>
inline T& operator --(T& a);
template <typename T>
inline T operator --(T& a, int);

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b);
template <typename T>
inline bool operator>(const T& a,const T& b);
template <typename T>
inline bool operator<=(const T& a,const T& b);
template <typename T>
inline bool operator>=(const T& a,const T& b);

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b);
template <typename T>
inline T operator |(const T& a, const T& b);
template <typename T>
inline T operator ^(const T& a, const T& b);
template <typename T>
inline T operator <<(const T& a, const T& b);
template <typename T>
inline T operator >>(const T& a, const T& b);

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b);
template <typename T>
inline T& operator %=(T& a, const T& b);
template <typename T>
inline T& operator ^=(T& a, const T& b);
template <typename T>
inline T& operator >>=(T& a, const T& b);

// arithmetic operators
template <typename T>
inline T operator +(const T& a, const T& b)
{
	T result = a;
	return result += b;
}

template <typename T>
inline T operator -(const T& a, const T& b)
{
	T result = a;
	return result -= b;
}

template <typename T>
inline T operator +(const T& a)
{
	return a;
}

template <typename T>
inline T operator *(const T& a, const T& b)
{
	T result = a;
	return result *= b;
}

template <typename T>
inline T operator /(const T& a, const T& b)
{
	T result = a;
	return result /= b;
}

template <typename T>
inline T operator %(const T& a, const T& b)
{
	T result = a;
	return result %= b;
}

template <typename T>
inline T& operator ++(T& a)
{
	return a += 1;
}

template <typename T>
inline T operator ++(T& a, int)
{
	T result = a;
	++a;
	return result;
}

template <typename T>
inline T& operator --(T& a)
{
	return a -= 1;
}

template <typename T>
inline T operator --(T& a, int)
{
	T result = a;
	--a;
	return result;
}

// comparison operators
template <typename T>
inline bool operator!=(const T& a,const T& b)
{
	return !(a == b);
}

template <typename T>
inline bool operator>(const T& a,const T& b)
{
	return b < a;
}

template <typename T>
inline bool operator<=(const T& a,const T& b)
{
	return !(a > b);
}

template <typename T>
inline bool operator>=(const T& a,const T& b)
{
	return !(a < b);
}

// bitwise operators
template <typename T>
inline T operator &(const T& a, const T& b)
{
	T result = a;
	return result &= b;
}

template <typename T>
inline T operator |(const T& a, const T& b)
{
	T result = a;
	return result |= b;
}

template <typename T>
inline T operator ^(const T& a, const T& b)
{
	T result = a;
	return result ^= b;
}

template <typename T>
inline T operator <<(const T& a, const T& b)
{
	T result = a;
	return result <<= b;
}

template <typename T>
inline T operator >>(const T& a, const T& b)
{
	T result = a;
	return result >>= b;
}

// compound assignment operators
template <typename T>
inline T& operator -=(T& a, const T& b)
{
	return a += -b;
}

template <typename T>
inline T& operator %=(T& a, const T& b)
{
	return a -= a / b * b;
}

template <typename T>
inline T& operator ^=(T& a, const T& b)
{
	return a = ~(a & b) & (a | b);
}

template <typename T>
inline T& operator >>=(T& a, const T& b)
{
	return a <<= -b;
}

#endif // RELOP_H_INCLUDED

#ifndef MOD
#define MOD 1000000007
#endif // MOD

class Remainder
{
public:
    long long value;
    Remainder(long long = 0);
};

inline Remainder operator + (const Remainder & l, const Remainder & r);

inline Remainder operator - (const Remainder & l, const Remainder & r);

inline Remainder operator * (const Remainder & l, const Remainder & r);

inline Remainder operator / (const Remainder & l, const Remainder & r);

inline Remainder & operator++(Remainder & r);

inline Remainder operator++(Remainder & r, int);

inline Remainder & operator--(Remainder & r);

inline Remainder operator--(Remainder & r, int);

inline Remainder operator + (const Remainder & r);

inline Remainder operator - (const Remainder & r);

inline Remainder & operator += (Remainder & l, const Remainder & r);

inline Remainder & operator -= (Remainder & l, const Remainder & r);

inline Remainder & operator *= (Remainder & l, const Remainder & r);

inline Remainder & operator /= (Remainder & l, const Remainder & r);

inline Remainder operator ~ (const Remainder & l);

inline bool operator == (const Remainder & l, const Remainder & r);

inline bool operator < (const Remainder & l, const Remainder & r);

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o);

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o);

inline Remainder::Remainder(long long r)
{
    value = r;
	value %= MOD;
	if (value < 0)
	{
		value += MOD;
	}
}

inline Remainder operator + (const Remainder & l, const Remainder & r) // A + B
{
   Remainder oResult(l.value + r.value);
   return oResult ;
}

inline Remainder operator - (const Remainder & l, const Remainder & r) // A - B
{
   Remainder oResult(l.value - r.value);
   return oResult ;
}

inline Remainder operator * (const Remainder & l, const Remainder & r) // A * B
{
   Remainder oResult(l.value * r.value);
   return oResult ;
}

inline Remainder operator / (const Remainder & l, const Remainder & r) // A / B
{
	long long x, y;
	gcd(r.value, static_cast<long long>(MOD), x, y);
   Remainder oResult(l * x);
   return oResult ;
}

inline Remainder & operator++(Remainder & r) // ++A
{
   r += 1;
   return r ;
}

inline Remainder operator++(Remainder & r, int) // A++
{
   Remainder oCopy(r);
   r += 1;
   return oCopy ;
}

inline Remainder & operator--(Remainder & r) // --A
{
   r -= 1;
   return r ;
}

inline Remainder operator--(Remainder & r, int) // A--
{
   Remainder oCopy(r);
   r -= 1;
   return oCopy ;
}

inline Remainder operator + (const Remainder & r) // +A
{
   return r ;
}

inline Remainder operator - (const Remainder & r) // -A
{
	Remainder temp(-(r.value));
   return temp;
}

inline Remainder & operator += (Remainder & l, const Remainder & r) // A += B
{
   l = l + r;

   return l ;
}

inline Remainder & operator -= (Remainder & l, const Remainder & r) // A -= B
{
   l = l - r;

   return l ;
}

inline Remainder & operator *= (Remainder & l, const Remainder & r) // A *= B
{
   l = l * r;

   return l ;
}

inline Remainder & operator /= (Remainder & l, const Remainder & r) // A /= B
{
   l = l / r;

   return l ;
}

inline Remainder operator ~ (const Remainder & l) // ~A
{
   Remainder oResult(-l);
   return oResult ;
}

inline bool operator == (const Remainder & l, const Remainder & r) // A == B
{
   return l.value == r.value ;
}

inline bool operator < (const Remainder & l, const Remainder & r) // A < B
{
   return l.value < r.value ;
}

// OUTPUT << A
template <typename charT, typename traits>
inline std::basic_ostream<charT,traits> & operator << (std::basic_ostream<charT,traits> & os, const Remainder & o)
{
   os << o.value;
   return os ;
}

// INPUT >> A
template <typename charT, typename traits>
inline std::basic_istream<charT,traits> & operator >> (std::basic_istream<charT,traits> & is, Remainder & o)
{
   is >> o.value;
   o = Remainder(o);
   return is ;
}

#endif // MOD_H_INCLUDED

#include <vector>
#include <cstdio>

int main()
{
	int n;
	scanf("%d", &n);

	int* s = new int[n];
	unordered_map<int,int> f;
	unordered_map<int,vector<int>> b;
	rep (i, n)
	{
		int from, to;
		scanf("%d%d", &from, &to);
		s[i] = from;
		f[from] = to;
		b[to].push_back(from);
	}

	Remainder result = 1;

    unordered_set<int> considered;
    rep (i, n)
    {
    	int start = s[i];
        int spot = s[i];
        if (considered.count(spot))
		{
            continue;
		}

		unordered_set<int> visited;
		bool loop = false;
        while (f.find(spot) != f.end())
		{
			visited.insert(spot);
            spot = f[spot];
            if (visited.count(spot))
			{
				loop = true;
                break;
			}
		}

		if (considered.count(spot))
		{
			continue;
		}

		if (loop)
		{
			spot = start;
			unordered_set<int> visited;
			while (f.find(spot) != f.end())
			{
				considered.insert(spot);
				visited.insert(spot);
				spot = f[spot];
				if (visited.count(spot))
				{
					break;
				}
			}

			if (spot != f[spot])
			{
                result *= 2;
			}

		}

		vector<int> togo;
		togo.push_back(spot);

		int spots = 0;

		int index = 0;

		while (index != togo.size())
		{
			++spots;
			int spot = togo[index];
			++index;
            considered.insert(spot);

            int bindex = 0;
            while (bindex != b[spot].size())
			{
				int to = b[spot][bindex];
				if (!considered.count(to))
                {
                	togo.push_back(b[spot][bindex]);
                }
                ++bindex;
			}
		}

		if (!loop)
		{
			result *= spots;
		}
    }

	cout << result;

	eOP();
}

inline void eOP()
{
	cout << output.str();
	output.str(string());
	exit(0);
}