#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define repu(i,x,y) for (int i=x; i<=y; ++i)
using namespace std;

typedef long long LL;
const int p=1000000007;
int n,fac[200100],inv[200100],ans,cntv,cnte,a[200100],deg[200100],link[200100],s[200100];
bool flag[200100];
struct edge
{
    int v;
    edge *nxt;
} pool[600100],*tp=pool,*fst[200100],*fst2[200100];

int getint()
{
    char ch;
    while (!isdigit(ch=getchar()));
    int x=ch-'0';
    for (; isdigit(ch=getchar()); x=x*10+ch-'0');
    return x;
}

int c(int n,int m)
{
    return LL(fac[n])*inv[m]%p*inv[n-m]%p;
}

void addedge(int u,int v,edge **fst)
{
    *tp=(edge){v,fst[u]},fst[u]=tp++;
}

void dfs1(int x)
{
    flag[x]=1,a[++cntv]=x;
    for (edge *i=fst[x]; i; i=i->nxt)
        if (flag[i->v])
            ++cnte,++deg[x],++deg[i->v];
    for (edge *i=fst[x]; i; i=i->nxt)
        if (!flag[i->v])
            dfs1(i->v);
}

int dfs2(int x)
{
    int ret=s[x]=1;
    for (edge *i=fst2[x]; i; i=i->nxt)
    {
        ret=LL(ret)*dfs2(i->v)%p;
        s[x]+=s[i->v],ret=LL(ret)*c(s[x]-1,s[i->v])%p;
    }
    return ret;
}

int calc()
{
    static bool flag[200100];
    edge *t=tp;
    repu(i,1,cntv)
        flag[a[i]]=0;
    repu(i,1,cntv)
        for (edge *j=fst[a[i]]; j; j=j->nxt)
            if (j->v<link[a[i]])
                addedge(a[i],j->v,fst2),flag[j->v]=1;
    int sum=0,ret=1;
    repu(i,1,cntv)
        if (!flag[a[i]])
        {
            ret=LL(ret)*dfs2(a[i])%p;
            ret=LL(ret)*c(sum+=s[a[i]],s[a[i]])%p;
        }
    tp=t;
    repu(i,1,cntv)
        fst2[a[i]]=0;
    return ret;
}

int solve(int x)
{
    cntv=cnte=0,dfs1(x);
    if (cntv!=cnte)
    {
        puts("0");
        exit(0);
    }
    repu(i,1,cntv)
        if (deg[a[i]]==1)
            for (int j=a[i],nxt=0; j; deg[j]=0,j=nxt,nxt=0)
                for (edge *k=fst[j]; k; k=k->nxt)
                    if (deg[k->v]>1)
                    {
                        link[j]=k->v;
                        if (--deg[k->v]==1)
                            nxt=k->v;
                    }
    static int cyc[200100],tot;
    repu(i,1,cntv)
        if (deg[a[i]]>1)
        {
            cyc[tot=1]=a[i];
            while (tot==1 || cyc[tot]!=a[i])
                for (edge *j=fst[cyc[tot]]; j; j=j->nxt)
                    if (deg[j->v]>1 && cyc[tot-1]!=j->v)
                    {
                        cyc[++tot]=j->v;
                        break;
                    }
            --tot;
            break;
        }
    repu(i,1,tot)
        link[cyc[i]]=cyc[i+1];
    int sum=calc();
    repu(i,1,tot)
        link[cyc[i+1]]=cyc[i];
    (sum+=calc())%=p,ans=LL(ans)*sum%p;
    return cntv;
}

int main()
{
    n=getint(),ans=1;
    repu(i,1,n*2)
    {
        int u=getint(),v=getint()+n;
        addedge(u,v,fst),addedge(v,u,fst);
    }
    fac[0]=fac[1]=inv[0]=inv[1]=1;
    repu(i,2,n*2)
        inv[i]=LL(p-p/i)*inv[p%i]%p;
    repu(i,2,n*2)
        fac[i]=LL(fac[i-1])*i%p,inv[i]=LL(inv[i-1])*inv[i]%p;
    int sum=0;
    repu(i,1,n*2)
        if (!flag[i])
        {
            int cnt=solve(i);
            ans=LL(ans)*c(sum+=cnt,cnt)%p;
        }
    printf("%d\n",ans);
    return 0;
}

Measured memory_bytes: 18688