#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <cmath>
#include <cstdio>
#include <bitset>
#include <vector>
#include <cstring>
#include <cassert>
#include <iostream>
#include <algorithm>
using namespace std;
typedef double db;
typedef long long ll;
typedef long double ld;
typedef vector<int> vi;
typedef pair<int,int> pa;
typedef unsigned int uint;
typedef unsigned long long ull;
#define w1 first
#define ls (x<<1)
#define w2 second
#define ins insert
#define rs (x<<1|1) 
#define mp make_pair
#define pb push_back
#define mid ((l+r)>>1)
#define sqr(x) ((x)*(x))
#define cle(x) ((x).clear())
#define lowbit(x) ((x)&(-x))
#define SZ(x) (int((x).size()))
#define All(x) (x).begin(),(x).end()
#define ms(x,y) memset(x,y,sizeof (x))
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define rep2(i,a,b) for(int (i)=(a);(i)<(b);(i)++)
#define per(i,a,b) for(int (i)=(a);(i)>=(b);(i)--)
#define Rep(p,x) for(int (p)=head[(x)];(p);(p)=nxt[(p)]) 
#define Rep2(p,x) for(int (p)=cur[(x)];(p);(p)=nxt[(p)])
template<class T>inline void read(T&num){
	num=0;T f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
	num*=f;
}
inline int getgcd(int x,int y){if(!x)return y;return getgcd(y%x,x);}
inline int power(int x,int k,int p){int res=1;for(;k;k>>=1,x=(ll)x*x%p)if(k&1)res=(ll)res*x%p;return res;}
const double pi=acos(-1);	
inline void judge(){
	freopen("input.txt","r",stdin);
} 
//********************************head*************************************
const int maxn=2e5+5,maxm=1e6+5,mod=1e9+7;
int n,tot,top;
int fac[maxn],ifac[maxn];
int head[maxn],des[maxm],nxt[maxm];
int vis[maxn],st[maxn],incir[maxn],is_root[maxn];
vector<int>cir,V,E;
vector<int>e[maxn];
void dfs(int x,int fa){
	vis[x]=1;
	V.pb(x);
	st[++top]=x;
	Rep(p,x){
		if(des[p]!=fa){
			if(!vis[des[p]])dfs(des[p],x);
			else if(!SZ(cir)){
				int now=top;
				while(st[now]!=des[p])cir.pb(st[now--]);
				cir.pb(des[p]);
			}
		}
		E.pb(p);
	}
	top--;
}
void adde(int x,int y){
	des[++tot]=y;nxt[tot]=head[x];head[x]=tot;
}
int C(int n,int m){
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
struct node{
	int sz,f;
	node(){sz=0;f=1;}
	node(int _sz,int _f){sz=_sz;f=_f;}
	friend node operator*(node a,node b){
		node c;
		c.sz=a.sz+b.sz;
		c.f=1ll*C(c.sz,a.sz)*a.f%mod*b.f%mod;
		return c;
	}
	friend node operator+(node a,node b){
		node c;
		if(a.sz!=b.sz)assert(0);
		c.sz=a.sz;
		c.f=(a.f+b.f)%mod;
		return c;
	}
};
void dfs_tree(int x,int fa){
	Rep(p,x)if(des[p]!=fa&&!incir[des[p]]){
		dfs_tree(des[p],x);
		if(des[p]<fa)e[x].pb(des[p]),is_root[des[p]]=0;
	}
}
node dfs_node(int x,int fa){
	node res(0,1);
	rep2(i,0,SZ(e[x]))res=res*dfs_node(e[x][i],x);
	res.sz++;
	return res;
}
int main(){
	read(n);
	fac[0]=1;rep(i,1,2*n)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[2*n]=power(fac[2*n],mod-2,mod);per(i,2*n-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
	rep(i,1,2*n){
		int x,y;read(x);read(y);
		adde(x,y+n);
		adde(y+n,x);
	}
	node ans(0,1);
	rep(i,1,n)if(!vis[i]){
		dfs(i,0);
		if(SZ(E)!=SZ(V)*2)return puts("0"),0;
		rep2(i,0,SZ(cir))incir[cir[i]]=1;
		//1
		node res1(0,1);
		rep2(i,0,SZ(V))is_root[V[i]]=1;
		rep2(i,0,SZ(cir)){
			int x=cir[i],y=cir[(i+1)%SZ(cir)];
			dfs_tree(x,0);
			Rep(p,x)if(des[p]<y)e[x].pb(des[p]),is_root[des[p]]=0;
		}
		rep2(i,0,SZ(V))if(is_root[V[i]])res1=res1*dfs_node(V[i],0);
		rep2(i,0,SZ(V))e[V[i]].clear();
		//2
		node res2(0,1);
		rep2(i,0,SZ(V))is_root[V[i]]=1;
		reverse(All(cir));
		rep2(i,0,SZ(cir)){
			int x=cir[i],y=cir[(i+1)%SZ(cir)];
			dfs_tree(x,0);
			Rep(p,x)if(des[p]<y)e[x].pb(des[p]),is_root[des[p]]=0;
		}
		rep2(i,0,SZ(V))if(is_root[V[i]])res2=res2*dfs_node(V[i],0);
		rep2(i,0,SZ(V))e[V[i]].clear();

		ans=ans*(res1+res2);

		V.clear();E.clear();cir.clear();
		rep2(i,0,SZ(cir))incir[cir[i]]=0;
		rep2(i,0,SZ(V))is_root[V[i]]=0;
	}
	printf("%d\n",ans.f);
	return 0;
}

Measured memory_bytes: 26984