#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef pair<int , int> P2;
typedef pair<pair<int , int> , int> P3;
typedef pair<pair<int , int> , pair<int , int> > P4;
#define PB(a) push_back(a)
#define MP(a , b) make_pair((a) , (b))
#define M3P(a , b , c) make_pair(make_pair((a) , (b)) , (c))
#define M4P(a , b , c , d) make_pair(make_pair((a) , (b)) , make_pair((c) , (d)))
#define repp(i,a,b) for(int i = (int)(a) ; i < (int)(b) ; ++i)
#define repm(i,a,b) for(int i = (int)(a) ; i > (int)(b) ; --i)

const int UF_MAX = 200020;

class UF{
	int x[UF_MAX];
	int co;
	
public:
	
	UF(){
		fill(x,x+UF_MAX,-1);
		co = 0;
	}
	
	int boss(int a){
		int s = a;
		while(x[s] > -1) s = x[s];
		if(s != a) x[a] = s;
		return s;
	}
	
	void uni(int a , int b){
		int s = boss(a);
		int t = boss(b);
		if(s != t){
			++co;
			if(x[s] < x[t]){
				x[s] += x[t];
				x[t] = s;
			} else {
				x[t] += x[s];
				x[s] = t;
			}
		}
	}
	
	bool find(int a , int b){
		return boss(a) == boss(b);
	}
	
	int count(){
		return co;
	}
	
	int member(int a){
		return -x[boss(a)];
	}
} uf;

const int MC = 100010;
const LL mod = 1e9 + 7;
int N;
int x[MC*2] , y[MC*2];
vector<int> V[MC*2];
vector<int> C[MC*2];
vector<int> G[MC*2];
vector<int> rG[MC*2];
int e[MC*2];
int al[MC*2];
int co[MC*2];
int sz[MC*2];
LL h[MC*2];
LL fct[MC*2];
LL inv[MC*2];
LL ans;

void build(){
	fct[0] = fct[1] = 1;
	repp(i,2,MC*2){
		fct[i] = fct[i-1] * i % mod;
	}
	LL x = fct[MC*2-1];
	inv[MC*2-1] = 1;
	for(int i = mod - 2 ; i > 0 ; i >>= 1){
		if(i % 2 == 1) (inv[MC*2-1] *= x) %= mod;
		(x *= x) %= mod;
	}
	repm(i,MC*2-1,0){
		inv[i-1] = inv[i] * i % mod;
	}
}

LL fanc(int z){
	queue<int> Q;
	LL k = fct[(int)C[z].size()];
	for(auto u : C[z]) rG[u].clear();
	for(auto u : C[z]){
		G[u].clear();
		for(auto w : V[u]){
			if(w == al[u]) break;
			G[u].PB(w);
			rG[w].PB(u);
		}
		sz[u] = 0;
		h[u] = 1;
		co[u] = G[u].size();
		if(co[u] == 0) Q.push(u);
		//cerr << u << ' ' << al[u] << endl;
	}
	while(!Q.empty()){
		int u = Q.front(); Q.pop();
		sz[u] = 1;
		for(auto w : G[u]){
			(h[u] *= h[w]) %= mod;
			(h[u] *= inv[sz[w]]) %= mod;
			sz[u] += sz[w];
		}
		(h[u] *= fct[sz[u]-1]) %= mod;
		//cerr << u << ' ' << h[u] << ' ' << sz[u] << endl;
		if(rG[u].size() == 0){
			(k *= h[u]) %= mod;
			(k *= inv[sz[u]]) %= mod;
		}
		for(auto w : rG[u]){
			--co[w];
			if(co[w] == 0) Q.push(w);
		}
	}
	//cerr << k << endl;
	return k;
}

LL calc(int z){
	queue<int> Q;
	int t = 0;
	for(auto u : C[z]) if(V[u].size() == 1) Q.push(u);
	while(!Q.empty()){
		int p = Q.front(); Q.pop();
		for(auto u : V[p]){
			if(al[u] == 0){
				al[p] = u;
				++co[u];
				++t;
				if(V[u].size() == co[u] + 1) Q.push(u);
			}
		}
	}
	int r,s;
	for(auto u : C[z]){
		if(al[u] == 0){
			r = s = u;
			break;
		}
	}
	while(C[z].size() > t + 1){
		for(auto u : V[r]){
			if(al[u] == 0){
				al[r] = u;
				r = u;
				++t;
				break;
			}
		}
	}
	al[r] = s;
	LL rv = fanc(z);
	queue<P2> Q2;
	r = s;
	while(Q2.empty() || r != s){
		Q2.push(MP(al[r],r));
		r = al[r];
	}
	while(!Q2.empty()){
		al[Q2.front().first] = Q2.front().second;
		Q2.pop();
	}
	return (rv + fanc(z)) % mod;
}

int main(){
	build();
	cin >> N;
	repp(i,0,2*N){
		cin >> x[i] >> y[i];
		V[x[i]].PB(MC+y[i]);
		V[MC+y[i]].PB(x[i]);
		uf.uni(x[i],MC+y[i]);
	}
	repp(i,1,N+1){
		C[uf.boss(i)].PB(i);
		e[uf.boss(i)] += V[i].size();
		C[uf.boss(MC+i)].PB(MC+i);
		e[uf.boss(MC+i)] += V[MC+i].size();
		sort(V[i].begin(),V[i].end());
		sort(V[MC+i].begin(),V[MC+i].end());
	}
	ans = fct[2*N];
	repp(i,1,N+1){
		if(uf.boss(i) == i){
			if(C[i].size() * 2 != e[i]){
				cout << 0 << endl;
				return 0;
			}
			(ans *= calc(i)) %= mod;
			(ans *= inv[(int)C[i].size()]) %= mod;
		}
		if(uf.boss(MC+i) == MC+i){
			if(C[MC+i].size() * 2 != e[MC+i]){
				cout << 0 << endl;
				return 0;
			}
			(ans *= calc(MC+i)) %= mod;
			(ans *= inv[(int)C[MC+i].size()]) %= mod;
		}
	}
	cout << ans << endl;
	return 0;
}


Measured memory_bytes: 42872