#include<bits/stdc++.h>
#define FR(i,a,b) for(int i=a;i>=b;i--)
#define FO(i,a,b) for(int i=a;i<=b;i++)
#define FE(i,a,b) for(int i=a;i<b;i++)
#define R(i) i=read()
using namespace std;
typedef long long ll;
const int N=200005,MOD=1e9+7;
int fac[N+10],inv[N+10],head[N],nxt[2*N],to[2*N];
int pd[N],vis[N],in_cycle[N],f[N],sz[N],instack[N],use[2*N],ass[N],dg[N];
int n,t,find_cycle,node_cnt,edge_cnt;
struct ANS {
	int size,ans;
};
stack <int> S;
vector <int> E[N],cycle,Node;
vector <ANS> Ans;
int read() {
	int x=0;char c=getchar();
	while((c<48||c>57)&&c!='-') c=getchar();
	if(c=='-') {c=getchar();while(c>=48&&c<=57) x=x*10-c+48,c=getchar();}
	else while(c>=48&&c<=57) x=x*10+c-48,c=getchar();
	return x;
}
void add(int x,int y) {
	nxt[++t]=head[x],head[x]=t,to[t]=y;
//	cout<<x<<" ---> "<<y<<endl;
}
int qmd(int a,int b,int p) {
	int t=1;
	while(b) {
		if(b&1) t=(ll) t*a%MOD;
		a=(ll) a*a%MOD;
		b>>=1;
	}
	return t;
}
void dfs_cycle(int u,int fa) {
	S.push(u);instack[u]=1;
	for(int i=head[u];i!=-1;i=nxt[i]) {
		int v=to[i];
		if(v==fa) continue;
		if(instack[v]) {
			find_cycle=1;
			int now=-1;
			while(now!=v) {
				now=S.top();S.pop();instack[now]=0;
				cycle.push_back(now),in_cycle[now]=1;
			}
		}
		else dfs_cycle(v,u); 
		if(find_cycle) return ;
	}
	S.pop(),instack[u]=0;
}
void dfs_all(int u,int fa) {
	vis[u]=1,Node.push_back(u);node_cnt++;
	for(int i=head[u];i!=-1;i=nxt[i]) {
		int v=to[i];
		if(!use[i]&&!use[i^1]) edge_cnt++,use[i]=use[i^1]=1;
		if(!vis[v]&&v!=fa) dfs_all(v,u);
	}
}
void dfs(int u,int fa) {
	pd[u]=1;
	for(int i=head[u];i!=-1;i=nxt[i]) {
		int v=to[i];
		if(!pd[v]&&v!=fa) 
			dfs(v,u);
	}
	if(!in_cycle[u]) ass[u]=fa;
}
void dfs_cal(int u) {
	int lim=E[u].size(),sum=0,mul=1,aans;
	FE(i,0,lim) {
		dfs_cal(E[u][i]);
		sum+=sz[E[u][i]],mul=(ll) mul*f[E[u][i]]%MOD;
	}
	aans=fac[sum];
	FE(i,0,lim)
		aans=(ll) aans*inv[sz[E[u][i]]]%MOD;
	aans=(ll) aans*mul%MOD;
	sz[u]=sum+1,f[u]=aans;
}
int work(int u) {
	find_cycle=0,cycle.clear(),Node.clear();
	while(!S.empty()) instack[S.top()]=0,S.pop();
	int l_node_cnt=node_cnt,l_edge_cnt=edge_cnt;
	dfs_all(u,0);
	if(node_cnt-l_node_cnt!=edge_cnt-l_edge_cnt) return 0;
	dfs_cycle(u,0);
	
//	int tmp=cycle.size();
//	cout<<"cycle : ";
//	FE(i,0,tmp) cout<<cycle[i]<<' ';
//	cout<<endl;
	
	dfs(cycle[0],0);
	
	int lim=cycle.size();
	FE(i,0,lim) ass[cycle[i]]=cycle[(i-1+lim)%lim];
	lim=Node.size();
	FE(i,0,lim) E[Node[i]].clear(),dg[Node[i]]=0;	//先清零dg[] 
	FE(i,0,lim) {
		int u=Node[i];
		for(int j=head[u];j!=-1;j=nxt[j]) {
			int v=to[j];
			if(v<ass[u]) 
				E[u].push_back(v),dg[v]++;
//				cout<<u<<" ---> "<<v<<endl;
		}
	}
	
//	cout<<endl<<endl;
	
	
	E[0].clear();
	FE(i,0,lim) if(dg[Node[i]]==0) E[0].push_back(Node[i]);
	f[0]=0;
	dfs_cal(0);
	int ans1=f[0];
	lim=cycle.size();
	FE(i,0,lim) ass[cycle[i]]=cycle[(i+1)%lim];
	lim=Node.size();
	FE(i,0,lim) E[Node[i]].clear(),dg[Node[i]]=0;
	FE(i,0,lim) {
		int u=Node[i];
		for(int j=head[u];j!=-1;j=nxt[j]) {
			int v=to[j];
			if(v<ass[u]) 
				E[u].push_back(v),dg[v]++;
//				cout<<u<<" ---> "<<v<<endl;
		}
	}
	E[0].clear();
	FE(i,0,lim) if(dg[Node[i]]==0) E[0].push_back(Node[i]);
	f[0]=0;
	dfs_cal(0);
	int ans2=f[0];
	Ans.push_back((ANS) {Node.size(),(ans1+ans2)%MOD});
	return 1;
}
void init() {
	fac[0]=inv[0]=1;
	FO(i,1,N) 
		fac[i]=((ll)fac[i-1]*i)%MOD;
	FO(i,1,N) inv[i]=qmd(fac[i],MOD-2,MOD);
	memset(head,-1,sizeof(head));
	t=-1;
}
int main() {
//	freopen("1.in","r",stdin);
	init();
	cin>>n;
	int a,b;
	FO(i,1,2*n) cin>>a>>b,add(a,n+b),add(n+b,a);
	FO(i,1,2*n) 
		if(!vis[i])
			if(!work(i)) {cout<<0;return 0;}
	int lim=Ans.size(),sum=0,mul=1,ans;
	FE(i,0,lim) 
		sum+=Ans[i].size,mul=(ll) mul*Ans[i].ans%MOD;
	ans=fac[sum];
	FE(i,0,lim)
		ans=(ll) ans*inv[Ans[i].size]%MOD;
	ans=(ll) ans*mul%MOD;
	cout<<ans;
	return 0;
}


Measured memory_bytes: 26228