/*program by mangoyang*/
#pragma GCC optimize("Ofast", "inline")
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
	int ch = 0, f = 0; x = 0;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
	if(f) x = -x;
}
#define fi first
#define se second
const int N = 400005, mod = 1e9 + 7;
vector<int> g[N];
int inv[N], n;
inline int Pow(int a, int b){
	int ans = 1;
	for(; b; b >>= 1, a = 1ll * a * a % mod)
		if(b & 1) ans = 1ll * ans * a % mod;
	return ans;
}
namespace Camlia{
	vector<int> e[N];
	int sz[N], deg[N];
	inline int dfs(int u, int fa){
		ll tmp = 1; sz[u] = 1;
		for(auto v : e[u]) if(v != fa){
			(tmp *= dfs(v, u)) %= mod;
			sz[u] += sz[v];
		}
		return tmp * inv[sz[u]] % mod;
	}
	inline int gao(vector<pair<int, int> > &A){
		ll res = 1;
		for(auto x : A){
			deg[x.fi] = deg[x.se] = 0;
			e[x.fi].clear(), e[x.se].clear();
		}
		for(auto x : A)
			for(int i = 0; g[x.se][i] < x.fi; i++)
				e[x.se].push_back(g[x.se][i]), deg[g[x.se][i]]++;
		for(auto x : A){
			if(!deg[x.fi]) (res *= dfs(x.fi, 0)) %= mod, deg[x.fi]++;
			if(!deg[x.se]) (res *= dfs(x.se, 0)) %= mod, deg[x.se]++;
		}
		return res;
	}
}
namespace Rose{
	vector<int> cir[N];
	int vis[N], ins[N], inc[N], num;
	inline int getcircle(int u, int fa, vector<int> &A){
		if(ins[u]) return 1;
		ins[u] = 1;
		for(auto v : g[u]) if(v != fa){
			int gao = getcircle(v, u, A);
			if(gao == 0) continue;
			if(gao == 2) return 2;
			A.push_back(v);
			return u == A[0] ? 2 : 1;
		}
		return ins[u] = 0, 0;
	}
	inline pair<int, int> mark(int u){
		vis[u] = 1;
		pair<int, int> now; now.fi = 1, now.se = 0;
		for(auto v : g[u]){
			if(vis[v]){ now.se++; continue; }
			pair<int, int> tmp = mark(v);
			now.fi += tmp.fi, now.se += tmp.se + 1;
		}
		return now;
	}
	inline void dfs(int u, int fa, vector<pair<int, int> > &A){
		if(fa) A.push_back(make_pair(fa, u));
		for(auto v : g[u]) 
			if(v != fa && !inc[v]) dfs(v, u, A);
	}
	inline void gao(){
		ll res = 1;
		for(int i = 1; i <= 2 * n; i++) if(!vis[i]){
			pair<int, int> now = mark(i);
			if(2 * now.fi != now.se){ puts("0"); exit(0); }
			getcircle(i, 0, cir[++num]);
			for(auto x : cir[num]) inc[x] = 1;
			int size = cir[num].size();
			vector<pair<int, int> > Base, A, B;
			for(auto x : cir[num]) dfs(x, 0, Base);
			A = B = Base;
			for(int j = 1; j < size; j++)
				A.push_back(make_pair(cir[num][j-1], cir[num][j]));
			A.push_back(make_pair(cir[num][size-1], cir[num][0]));
			for(int j = 1; j < size; j++)
				B.push_back(make_pair(cir[num][j], cir[num][j-1]));
			B.push_back(make_pair(cir[num][0], cir[num][size-1]));
			(res *= (Camlia::gao(A) + Camlia::gao(B)) % mod) %= mod;
		}
		for(int i = 1; i <= 2 * n; i++) (res *= i) %= mod;
		printf("%lld\n", res);
	}
}
int main(){
	read(n);
	for(int i = 1, x, y; i <= 2 * n; i++){
		read(x), read(y), y += n;
		g[x].push_back(y), g[y].push_back(x);
	}
	for(int i = 1; i <= 2 * n; i++) 
		inv[i] = Pow(i, mod - 2);
	for(int i = 1; i <= 2 * n; i++)
		sort(g[i].begin(), g[i].end());
	Rose::gao();
	return 0;
}

Measured memory_bytes: 54000