#include <iostream>
#include <queue>
#include <vector>
#include <bitset>

#define fir first
#define sec second

using namespace std;
using LL = long long;
using pii = pair<int, int>;

const int maxN = 2e5 + 5;
const int mod = 1e9 + 7;

int n, ans = 1, curs, tmps;
int fac[maxN], inv[maxN];
int pre[maxN], deg[maxN], val[maxN], size[maxN], fa[maxN], prod[maxN];
bitset<maxN> vis;
vector<int> wib;
vector<pii> G[maxN];
vector<int> newG[maxN];

inline void Mod(int& x)
{ x >= mod ? x -= mod : x < 0 ? x += mod : 0; }

int QPow(int bas, int ind)
{
    int res = 1;
    while (ind)
    {
        if (ind & 1)
            res = (LL)res * bas % mod;
        bas = (LL)bas * bas % mod;
        ind >>= 1;
    }
    return res;
}

inline int C(int n, int m)
{ return (LL)fac[n] * inv[m] % mod * inv[n - m] % mod; }

void Init(int lim)
{
    fac[0] = inv[0] = 1;
    for (int i = 1; i <= lim; ++i)
        fac[i] = (LL)fac[i - 1] * i % mod;
    inv[lim] = QPow(fac[lim], mod - 2);
    for (int i = lim - 1; i; --i)
        inv[i] = (LL)inv[i + 1] * (i + 1) % mod;
}

void Topsort()
{
    static queue<int> q;
    for (int i = 1; i <= n; ++i)
    {
        if (deg[i] == 1)
            q.push(i);
        if (deg[i] == 0)
        {
            cout << 0 << endl;
            exit(0);
        }
    }
    while (!q.empty())
    {
        int u = q.front();
        deg[u] = -1, q.pop();
        for (auto i : G[u]) if (~deg[i.fir])
        {
            val[u] = i.sec;
            if (--deg[i.fir] == 1)
                q.push(i.fir);
            if (deg[i.fir] == 0)
            {
                cout << 0 << endl;
                exit(0);
            }
        }
    }
}

void DFS(int u)
{
    for (auto i : G[u]) if (deg[i.fir] == 2 and i.sec != val[u])
    {
        if (!pre[i.fir])
        {
            pre[i.fir] = u, val[i.fir] = i.sec;
            DFS(i.fir);
        }
        else
            pre[i.fir] = u, val[i.fir] = i.sec;
    }
}

void Getlink(int u)
{
    vis.set(u), wib.push_back(u);
    for (auto i : G[u]) if (!vis[i.fir])
        Getlink(i.fir);
}

void Getsize(int u)
{
    if (size[u])
        return;
    size[u] = prod[u] = 1;
    for (auto i : G[u])
        if (i.sec != val[u] and val[i.fir] < val[u])
        {
            fa[i.fir] = u;
            Getsize(i.fir);
            prod[u] = (LL)prod[u] * prod[i.fir] % mod;
            size[u] += size[i.fir];
        }
    prod[u] = (LL)prod[u] * size[u] % mod;
}

int Getans()
{
    int siz = 1, pd = 1;
    for (int i : wib)
        size[i] = fa[i] = 0;
    for (int i : wib)
        if (!fa[i])
            Getsize(i);
    for (int i : wib)
        if (!fa[i])
            siz += size[i], pd = (LL)pd * prod[i] % mod;
    tmps = siz - 1;
    return (LL)fac[siz] * QPow((LL)pd * siz % mod, mod - 2) % mod;
}

int rt;
void Rev(int u)
{
    if (pre[u] != rt)
        Rev(pre[u]);
    val[pre[u]] = val[u];
}

int main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    n <<= 1;
    for (int i = 1; i <= n; ++i)
    {
        int x, y;
        cin >> x >> y;
        G[x].emplace_back(y + (n >> 1), x + y);
        G[y + (n >> 1)].emplace_back(x, x + y);
        ++deg[x], ++deg[y + (n >> 1)];
        // cout << x << ' ' << y + (n >> 1) << ' ' << x + y << endl;
    }
    Init(maxN - 2), Topsort();
    //for (int i = 1; i <= n; ++i)
    //    cout << deg[i] << endl;
    for (int i = 1; i <= n; ++i)
        if (deg[i] == 2 and !pre[i])
        {
            pre[i] = -1, DFS(i);
            Getlink(i);
            int res = Getans(), tmp = val[i];
            rt = i, Rev(i), val[pre[i]] = tmp;
            // for (int i = 1; i <= n; ++i)
            // cout << val[i] << endl;
            Mod(res += Getans());
            ans = (LL)ans * res % mod * C(curs + tmps, tmps) % mod;
            curs += tmps;
            wib.clear();
            // cout << res << ' ' << tmps << ' ' << ans << endl;
        }
    cout << ans << endl;
    return 0;
}

Measured memory_bytes: 27256