#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <math.h>
#include <assert.h>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <algorithm>
#include <iostream>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <bitset>

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
#define Fi first
#define Se second
#define pb(x) push_back(x)
#define sz(x) ((int)(x).size())
#define rep(i, n) for(int i=0;i<n;i++)
#define all(x) (x).begin(), (x).end()
typedef tuple<int, int, int> t3;
typedef pair<ll, ll> pll;
typedef long double ldouble;
typedef pair<double, double> pdd;

const int MOD = 1e9 + 7;

vector <int> E[200020];
int deg[200020];
int N;

int p[200020]; int Find(int x) { return p[x] == x ? x : p[x] = Find(p[x]); }
int z[200020];
vector <int> C[200020];
ll ans;
ll F[200020];
ll IF[200020];

int pw(int x, int y = MOD - 2) {
	int res = 1;
	while(y) {
		if(y & 1) res = (ll)res * x % MOD;
		x = (ll)x * x % MOD;
		y >>= 1;
	}
	return res;
}

int chk[200020];

void dfs2(int x, vector <int> &u) {
	u.pb(x);
	chk[x] = 1;
	for(int e : E[x]) if(deg[e] > 0 && chk[e] == 0) dfs2(e, u);
}

int In[200020];

vector <int> E2[200020];

ll Get(vector<int> &a) {
	int sum = 0;
	for(int e : a) sum += e;
	ll res = F[sum];
	for(int e : a) res = res * IF[e] % MOD;
	return res;
}

ll TT;
int dfs3(int x, int fa) {
	chk[x] = 2;
	vector <int> v;
	int res = 1;
	for(int e : E2[x]) if(e != fa) {
		if(chk[e] == 2) {
			return -1;
		}
		int t = dfs3(e, x);
		if(t == -1) return -1;
		v.pb(t);
		res += t;
	}
	TT = TT * Get(v) % MOD;
	return res;
}

void solve(){
	F[0] = 1;
	for(int i=1;i<200020;i++) F[i] = (ll)i * F[i-1] % MOD;
	IF[200019] = pw((int)F[200019]);
	for(int i=200018;i>=0;i--) IF[i] = (ll)(i+1) * IF[i+1] % MOD;
	scanf("%d", &N);
	for(int i=1;i<=N+N;i++) p[i] = i;
	for(int i=1;i<=N+N;i++) {
		int x, y; scanf("%d%d", &x, &y);
		E[x].pb(N + y);
		E[N + y].pb(x);
		p[Find(N+y)] = Find(x);
	}
	for(int i=1;i<=N+N;i++) z[Find(i)]++;
	for(int i=1;i<=N+N;i++) C[Find(i)].pb(i);
	for(int i=1;i<=N+N;i++) deg[i] = sz(E[i]);
	queue <int> que;
	for(int i=1;i<=N+N;i++) if(deg[i] == 0) {
		puts("0");
		return;
	}
	for(int i=1;i<=N+N;i++) if(deg[i] == 1) {
		que.push(i);
	}
	while(!que.empty()) {
		int t = que.front(); que.pop();
		for(int e : E[t]) {
			if(deg[e] > 0) {
				--deg[e]; --deg[t];
				In[t] = e;
				if(deg[e] == 1) que.push(e);
			}
		}
	}
	ans = F[N+N];
	for(int i=1;i<=N+N;i++) ans = ans * IF[z[i]] % MOD;
	
	int deg2[200020] = {};
	
	for(int i=1;i<=N+N;i++) if(sz(C[i])) {
		int r = -1;
		for(int e : C[i]) {
			if(deg[e] > 0) { r = e; break; }
		}
		vector <int> cyc;
		dfs2(r, cyc);
		int m = sz(cyc);
		for(int e : C[i]) chk[e] = 1;
		
		ll sum = 0;
		
		for(int i=0;i<m;i++) In[cyc[i]] = cyc[(i+1)%m];
		
		for(int e : C[i]) {
			for(int f : E[e]) {
				if(In[f] > e) E2[f].pb(e), deg2[e]++;
			}
		}
		
		ll tans = 1;
		vector <int> v;
		int ok = 1;
		for(int e : C[i]) {
			if(chk[e] == 1 && deg2[e] == 0) {
				TT = 1;
				int x = dfs3(e, -1);
				if(x == -1) ok = 0;
				else v.pb(x), tans = tans * TT % MOD;
			}
		}
		tans = tans * Get(v) % MOD;
		for(int e : C[i]) if(chk[e] == 1) ok = 0;
		if(ok == 0) tans = 0;
		sum = (sum + tans) % MOD;
		
		for(int e : C[i]) E2[e].clear(), chk[e] = 1, deg2[e] = 0;
		
		for(int i=0;i<m;i++) In[cyc[i]] = cyc[(i+m-1)%m];
		
		for(int e : C[i]) {
			for(int f : E[e]) {
				if(In[f] > e) E2[f].pb(e), deg2[e]++;
			}
		}
		
		tans = 1;
		v.clear();
		ok = 1;
		for(int e : C[i]) {
			if(chk[e] == 1 && deg2[e] == 0) {
				TT = 1;
				int x = dfs3(e, -1);
				if(x == -1) ok = 0;
				else v.pb(x), tans = tans * TT % MOD;
			}
		}
		tans = tans * Get(v) % MOD;
		for(int e : C[i]) if(chk[e] == 1) ok = 0;
		if(ok == 0) tans = 0;
		sum = (sum + tans) % MOD;
		
		for(int e : C[i]) E2[e].clear(), chk[e] = 1;
		ans = ans * sum % MOD;
	}
	
	printf("%lld\n", ans);
}

int main(){
	int Tc = 1; //scanf("%d\n", &Tc);
	for(int tc=1;tc<=Tc;tc++){
		// printf("Case #%d: ", tc);
		solve();
	}
	return 0;
}

Measured memory_bytes: 33656