#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<stack>
#include<vector>
#include<set>
#define MOD 1000000007
#define ll long long
using namespace std;
inline int read(){
	int re=0,flag=1;char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') flag=-1;
		ch=getchar();
	}
	while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
	return re*flag;
}
ll inv[200010],fac[200010];
namespace topo{
	int first[200010],cnte;
	vector<int>e[200010];
	int in[200010];
	set<int>app;
	inline void add(int u,int v){
//		cout<<"		topo add "<<u<<' '<<v<<'\n';
		e[u].push_back(v);
		in[v]++;
	}
	int siz[200010];
	ll dfs(int u,int f){
		ll re=1;siz[u]=1;
//		cout<<"		topo dfs "<<u<<'\n';
		assert(u);
		for(auto v:e[u]){
			if(v==f) continue;
//			cout<<"			to "<<' '<<v<<' '<<u<<'\n';
			(re*=dfs(v,u))%=MOD;siz[u]+=siz[v];
		}
//		cout<<"		topo return "<<re<<' '<<siz[u]<<' '<<inv[siz[u]]<<' '<<re*inv[siz[u]]%MOD<<'\n';
		return re*inv[siz[u]]%MOD;
	}
	ll solve(){
		ll re=1,tmp;
//		cout<<"toposolve "<<app.size()<<'\n';
		for(auto u:app){
			if(!in[u]){
				tmp=dfs(u,0);
				(re*=tmp%MOD)%=MOD;
//				cout<<"appear "<<u<<' '<<re<<' '<<siz[u]<<' '<<fac[siz[u]]<<' '<<tmp<<'\n';
			}
		}
		for(auto u:app) e[u].clear(),in[u]=0;
		return re;
	}
}
vector<int>e[200010];
stack<int>s;
bool vis[200010],in[200010];int cnt1,cnt2,lped;
vector<int>cir;
void dfs(int u,int f){
	int i,v;cnt1++;s.push(u);
	vis[u]=1;
//	cout<<"dfs "<<u<<' '<<f<<'\n';
	for(i=0;i<e[u].size();i++){
		v=e[u][i];if(v==f||in[v]) continue;
		cnt2++;
		if(!lped&&vis[v]){
			lped=1;
//			cout<<"	get loop "<<v<<' '<<u<<'\n';
			while(s.top()!=v) cir.push_back(s.top()),in[s.top()]=1,s.pop();
			cir.push_back(s.top()),in[s.top()]=1,s.pop();
		}
		else if(!vis[v]){
//			cout<<"goto "<<v<<' '<<u<<'\n';
			dfs(v,u);
		}
	}
	if(!s.empty()&&s.top()==u) s.pop();
//	cout<<"finish "<<u<<'\n';
}
int ch[200010];
void dfs2(int u,int f){
//	cout<<"dfs2 "<<u<<' '<<f<<'\n';
	int i,v;
	for(i=0;i<e[u].size();i++){
		v=e[u][i];if(v==f||in[v]) continue;
		ch[v]=u;
		dfs2(v,u);
	}
}
void adde(int u,int f){
//	cout<<"adde "<<u<<' '<<f<<' '<<ch[u]<<'\n';
	topo::app.insert(u);
	for(auto v:e[u]){
		if(v==ch[u]) break;
		topo::add(u,v);
	}
	for(auto v:e[u]){
		if(v==f||in[v]) continue;
		adde(v,u);
	}
}
ll solve(int u){
//	cout<<"solve "<<u<<'\n';
	cnt1=cnt2=lped=0;
	dfs(u,0);
//	cout<<"fin dfs "<<cnt1<<' '<<cnt2<<'\n';
	if(cnt1!=cnt2) return 0;
	int i;ll re=0;
	for(i=0;i<cir.size();i++){
		dfs2(cir[i],0);
	}
	//first
	for(i=0;i<cir.size();i++){
		ch[cir[i]]=cir[(i+1)%cir.size()];
	}
	for(i=0;i<cir.size();i++){
		adde(cir[i],0);
	}
	re+=topo::solve();
	//second
	for(i=0;i<cir.size();i++){
		ch[cir[i]]=cir[(i-1+cir.size())%cir.size()];
	}
	for(i=0;i<cir.size();i++){
		adde(cir[i],0);
	}
	re+=topo::solve();
	topo::app.clear();
	for(i=0;i<cir.size();i++) in[i]=0;
	cir.clear();
//	cout<<"finsolve "<<topo::app.size()<<"\n";
	return re%MOD;
}
int n;
int main(){
	n=read();int i,t1,t2;
	memset(topo::first,-1,sizeof(topo::first));
	inv[1]=1;fac[1]=1;
	for(i=2;i<=n*2;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
	for(i=2;i<=n*2;i++) fac[i]=fac[i-1]*i%MOD;
	for(i=1;i<=n*2;i++){
		t1=read();t2=read();t2+=n;
		e[t1].push_back(t2);
		e[t2].push_back(t1);
	}
	for(i=1;i<=n*2;i++){
		if(e[i].size()) sort(e[i].begin(),e[i].end());
	}
	ll ans=1;
	for(i=1;i<=n*2;i++){
		if(!vis[i]) (ans=ans*solve(i))%=MOD;
	}
	cout<<(fac[2*n]*ans)%MOD<<'\n';
}

Measured memory_bytes: 37504