#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
typedef vector <int> vr;

const ld inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 200020;
const ll mod = 1e9 + 7;

inline ll power(ll x,ll y){
	y = ((y % (mod - 1)) + (mod - 1)) % (mod - 1);
//	if ( y < 0 ) return power(power(x,-y),mod - 2);
	ll res = 1;
	while ( y ){
		if ( y & 1 ) res = res * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return res;
}
struct node{
	int next,to;
}e[maxn * 2];
int head[maxn],cnt,n;
ll fac[maxn],inv[maxn],inv2[maxn],a[maxn],f[maxn];
vector <int> cir[maxn],vec[maxn],comp[maxn];
int flag;
int st[maxn],tops,vis[maxn],tag[maxn],q[maxn],hh,tt,deg[maxn],fa[maxn],sz[maxn];

void init(){
	fac[0] = inv[0] = 1;
	rep(i,1,2 * n ) fac[i] = fac[i - 1] * i % mod , inv[i] = power(fac[i],mod - 2);
}
inline void adde(int x,int y){
//	cout<<x<<" "<<y<<endl;
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int x,int fa){
//	cout<<x<<" "<<fa<<endl;
	if ( vis[x] ){
		flag = 1;
		repd(i,tops,1){
			int y = st[i];
			tag[y] = 1 , cir[cnt].pb(y);
			if ( y == x ) break;
		}
		return;
	}
	st[++tops] = x , vis[x] = 1;
	fore(i,x){
		if ( e[i].to == fa ) continue;
		dfs(e[i].to,x);
		if ( flag ) return;
	}
	tops--;
}
inline void adde2(int x,int y);
void dfs_e(int x,int fa){
	ll res = 1;
	if ( fa ){
		rvc(i,vec[x]){
			if ( fa <= vec[x][i] ) break;
			adde2(x,vec[x][i]);
		}		
	}
	fore(i,x){
		if ( e[i].to == fa || tag[e[i].to] ) continue;
		dfs_e(e[i].to,x);
	}
}

node e2[maxn * 2];
int head2[maxn],cnt2;
#define head head2
#define e e2
#define cnt cnt2
#define fore2(i,x) for (register int i = head2[x] ; i ; i = e2[i].next)
inline ll C(int n,int m){
	if ( n < 0 || m < 0 || n < m ) return 0;
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
inline void adde2(int x,int y){
//	cout<<x<<" "<<y<<endl;
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
	deg[y]++;
	fa[y] = x;
}

void clear(vector <int> &a){
	rvc(i,a){
		head[a[i]] = 0;
		deg[a[i]] = 0;
		fa[a[i]] = 0;
	}
	cnt2 = 0;
}

bool check(vector <int> a){
	int ecnt = 0;
	rvc(i,a){
		ecnt += deg[a[i]];
	}
//	cout<<ecnt<<" "<<a.size()<<endl;
	if ( ecnt != a.size() * 2 ) return 0;
	return 1;
}
ll topo(vr &a){
//	cout<<"getans\n";
	ll res = 1; int S = 0;
	tt = hh = 0;
	rvc(i,a){
		int x = a[i];
		if ( !deg[x] ) q[tt++] = x;
	}
	while ( hh < tt ){
		int x = q[hh++];
		fore2(i,x){
			deg[e[i].to]--;
			if ( deg[e[i].to] == 0 ) q[tt++] = e[i].to;
		}
	}
	repd(i,tt - 1,0){
		int x = q[i];
		f[x] = 1 , sz[x] = 0;
		fore2(j,x){
			sz[x] += sz[e[j].to];
			f[x] = f[x] * C(sz[x],sz[e[j].to]) % mod * f[e[j].to] % mod;
		}
		sz[x]++;
		if ( !fa[x] ){
		   	S += sz[x];
			res = res * f[x] % mod * C(S,sz[x]) % mod;
	//		cout<<x<<" "<<f[x]<<" "<<sz[x]<<endl;
		}
	}
//	cout<<"topo "<<res<<endl;
	return res;
}
ll solve(vector <int> &V,vector <int> &a){
	if ( !check(a) ) return 0;
	ll res = 0;
	clear(a);
	rvc(i,V){
		dfs_e(V[i],0);
	}
	int n = V.size(),last = V[0];
	rep(i,1,n - 1){
		int x = V[i];
		rvc(j,vec[x]){
			if ( vec[x][j] >= last ) break;
			adde2(x,vec[x][j]);
		}
		last = x;
	}
	rvc(j,vec[V[0]]){
		if ( vec[V[0]][j] >= last ) break;
		adde2(V[0],vec[V[0]][j]);	
	}
	res = topo(a);

	//倒着分配
	clear(a);
	rvc(i,V){
		dfs_e(V[i],0);
	}
	last = V[n - 1];
	repd(i,n - 2,0){
		int x = V[i];
		rvc(j,vec[x]){
			if ( vec[x][j] >= last ) break;
			adde2(x,vec[x][j]);
		}
		last = x;
	}
	rvc(j,vec[V[n - 1]]){
		if ( vec[V[n - 1]][j] >= last ) break;
		adde2(V[n - 1],vec[V[n - 1]][j]);	
	}
	res += topo(a);
	return res;
}
#undef e
#undef cnt
#undef head
int vis2[maxn];
void dfs2(int x){
	vis2[x] = 1;
	comp[cnt].pb(x);
	fore(i,x){
		if ( vis2[e[i].to] ) continue;
		dfs2(e[i].to);
	}
}
int main(){
	
	scanf("%d",&n);
	init();
	rep(i,1,n * 2){
		int x,y;
		scanf("%d %d",&x,&y);
		adde(x,y + n) , adde(y + n,x);
		deg[x]++ , deg[y + n]++;
		vec[x].pb(y + n);
		vec[y + n].pb(x);
	}
	rep(i,1,n * 2) sort(vec[i].begin(),vec[i].end());
	cnt = 0;
	rep(i,1,n * 2) if ( !vis2[i] ){
	   	++cnt , flag = 0 , dfs(i,0);
		if ( !flag ) return puts("0"),0;
		dfs2(i);
	}
	ll ans = 1; int S = 0;
	rep(i,1,cnt){
		S += comp[i].size();
		ans = ans * solve(cir[i],comp[i]) % mod * C(S,comp[i].size()) % mod;
	}
	cout<<ans<<endl;
}


Measured memory_bytes: 44004