#pragma GCC optimize(2, "Ofast", "inline")
#include <bits/stdc++.h>
#define fi first
#define se second
using namespace std;
typedef pair <int, int> pii;
 
const int N = 4e5 + 5, mod = 1e9 + 7;
int n, m, ans, ways;
int fac[N], inv[N];
int pre[N], rp[N][2], cp[N][2];
int deg[N], color[N], os[N];
int dir[N], id[N];
pii nowp, rep[N], a[N];
map <pii, int> exi;
vector <int> dlt, e[N], g[N], r[N], ance[N];
queue <int> sing;
inline int read () {
	int x = 0; char ch = getchar();
	while (ch < '0' || ch > '9') {
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x;
}
inline int power (int a, int b) {
    int ret = 1;
    for ( ; b; b >>= 1, a = 1ll * a * a % mod) {
        if (b & 1) {
            ret = 1ll * ret * a % mod;
        }
    }
    return ret;
}
void predo () {
    fac[0] = 1;
    for (int i = 1; i <= n + n; ++i) {
        fac[i] = 1ll * fac[i - 1] * i % mod;
    }
    inv[n + n] = power(fac[n + n], mod - 2);
    for (int i = n + n - 1; ~i; --i) {
        inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
    }
}
void adds (int x, int y) {
    g[x].push_back(y), g[y].push_back(x);
}
void cover (int x) {
    color[x] = m;
    r[m].push_back(x);
    if (!dir[x]) {
        ++os[m];
    }
    for (auto y : g[x]) {
        if (!color[y]) {
            cover(y);
        }
    }
}
void bring (int x, int c) {
    r[color[x]].clear();
    color[x] = c;
    r[c].push_back(x);
    for (auto y : ance[x]) {
        bring(y, c);
    }
}
struct Tr {
    int n, dg[N], subs[N], fa[N];
    vector <int> c[N];
    void init (int _n) {
        n = _n;
        for (int i = 0; i <= n; ++i) {
            dg[i] = subs[i] = 0;
            fa[i] = -1;
            c[i].clear();
        }
    }
    void add (int x, int y) {
        if (fa[y] == -1) {
            fa[y] = x;
            c[x].push_back(y), ++dg[y];
        }
    }
    int dp (int x, int p) {
        int ret = 1;
        subs[x] = 1;
        for (auto y : c[x]) {
            if (y != p) {
                ret = 1ll * ret * dp(y, x) % mod;
                subs[x] += subs[y];
                ret = 1ll * ret * inv[subs[y]] % mod;
            }
        }
        ret = 1ll * ret * fac[subs[x] - 1] % mod;
        return ret;
    }
} T;
int deter (int x, int f) {
    T.init(r[x].size());
    for (int i = 0; i < os[x]; ++i) {
        dir[r[x][i]] = ((i + f) & 1) + 1;
    }
    for (int i = 0; i < r[x].size(); ++i) {
        id[r[x][i]] = i;
    }
    for (int i = os[x], u, v; i < r[x].size(); ++i) {
        u = r[x][i], nowp = a[u];
        for (auto v : ance[u]) {
            T.add(i + 1, id[v] + 1);
        }
        if (os[x]) {
            if (dir[u] == 1) {
                v = rp[a[u].fi][0];
                if (a[u].se < a[v].se && dir[v] == 2) {
                    T.add(id[v] + 1, i + 1);
                } else {
                    v = rp[a[u].fi][1];
                    if (a[u].se < a[v].se && dir[v] == 2) {
                        T.add(id[v] + 1, i + 1);
                    }
                }
            } else {
                v = cp[a[u].se][0];
                if (a[u].fi < a[v].fi && dir[v] == 1) {
                    T.add(id[v] + 1, i + 1);
                } else {
                    v = cp[a[u].se][1];
                    if (a[u].fi < a[v].fi && dir[v] == 1) {
                        T.add(id[v] + 1, i + 1);
                    }
                }
            }
        }
    }
    for (int i = 0, u, v; i < os[x]; ++i) {
        u = r[x][i], v = r[x][(i + 1) % os[x]];
        if (dir[u] == 1 && dir[v] == 2) {
            if (a[u].fi == a[v].fi && a[u].se < a[v].se) {
                T.add((i + 1) % os[x] + 1, i + 1);
            }
            if (a[u].se == a[v].se && a[u].fi > a[v].fi) {
                T.add(i + 1, (i + 1) % os[x] + 1);
            }
        } else {
            if (a[u].fi == a[v].fi && a[u].se > a[v].se) {
                T.add(i + 1, (i + 1) % os[x] + 1);
            }
            if (a[u].se == a[v].se && a[u].fi < a[v].fi) {
                T.add((i + 1) % os[x] + 1, i + 1);
            }
        }
    }
    for (int i = 1; i <= T.n; ++i) {
        if (T.dg[i] == 0) {
            T.add(0, i);
        }
    }
    return T.dp(0, -1);
}
int main () {
	n = read(), predo();
    for (int i = 1, x, y; i <= n + n; ++i) {
    	x = read(), y = read();
        a[i] = make_pair(x, y);
        exi[a[i]] = i;
        y += n;
        e[x].push_back(y), e[y].push_back(x);
        ++deg[x], ++deg[y];
    }
    for (int i = 1; i <= n + n; ++i) {
        if (deg[i] == 0) {
            return puts("0"), 0;
        }
    }
    for (int i = 1; i <= n + n; ++i) {
        if (deg[i] == 1) {
            if (i <= n) {
                rep[i] = make_pair(i, e[i][0] - n);
                dir[exi[rep[i]]] = 2;
            } else {
                rep[i] = make_pair(e[i][0], i - n);
                dir[exi[rep[i]]] = 1;
            }
            sing.push(i), dlt.push_back(i);
        }
    }
    for ( ; !sing.empty(); ) {
        int x = sing.front(), z;
        sing.pop();
        for (auto y : e[x]) {
            if ((--deg[y]) == 1) {
                for (auto u : e[y]) {
                    if (deg[u] > 1) {
                        z = u;
                        break;
                    }
                }
                if (y <= n) {
                    rep[y] = make_pair(y, z - n);
                    dir[exi[rep[y]]] = 2;
                } else {
                    rep[y] = make_pair(z, y - n);
                    dir[exi[rep[y]]] = 1;
                }
                sing.push(y), dlt.push_back(y);
            }
        }
    }
    memset(deg, 0, sizeof deg);
    for (int i = 1, p, q, u, v; i <= n + n; ++i) {
        u = exi[rep[i]], p = dir[u];
        if (p) {
            for (auto j : e[i]) {
                v = exi[rep[j]], q = dir[v];
                if (!v) {
                    continue;
                }
                if (p == 1 && q == 2) {
                    if (rep[i].fi > rep[j].fi) {
                        ance[u].push_back(v), ++deg[v];
                    }
                } else {
                    if (rep[i].se > rep[j].se) {
                        ance[u].push_back(v), ++deg[v];
                    }
                }
            }
        }
    }
    for (auto x : dlt) {
        exi[rep[x]] = 0;
    }
    for (auto p : exi) {
        if (p.se) {
            if (rp[p.fi.fi][0]) {
                rp[p.fi.fi][1] = p.se;
                if (a[rp[p.fi.fi][0]].se > a[rp[p.fi.fi][1]].se) {
                    swap(rp[p.fi.fi][0], rp[p.fi.fi][1]);
                }
            } else {
                rp[p.fi.fi][0] = p.se;
            }
            if (cp[p.fi.se][0]) {
                cp[p.fi.se][1] = p.se;
                if (a[cp[p.fi.se][0]].fi > a[cp[p.fi.se][1]].fi) {
                    swap(cp[p.fi.se][0], cp[p.fi.se][1]);
                }
            } else {
                cp[p.fi.se][0] = p.se;
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        if (rp[i][0] && rp[i][1]) {
            adds(rp[i][0], rp[i][1]);
        }
        if (cp[i][0] && cp[i][1]) {
            adds(cp[i][0], cp[i][1]);
        }
    }
    for (int i = 1; i <= n + n; ++i) {
        if (!color[i]) {
            ++m, cover(i);
        }
    }
    for (int i = 1, ci; i <= n + n; ++i) {
        if ((int)r[color[i]].size() == 1) {
            nowp = a[i], ci = -1;
            if (dir[i] == 2) {
                if (cp[nowp.se][0]) {
                    ci = color[cp[nowp.se][0]];
                }
            } else {
                if (rp[nowp.fi][0]) {
                    ci = color[rp[nowp.fi][0]];
                }
            }
            if (~ci) {
                bring(i, ci);
            } else {
                if (!deg[i]) {
                    for (auto j : ance[i]) {
                        bring(j, color[i]);
                    }
                }
            }
        }
    }
    ans = 1, ways = 1;
    for (int i = 1, tmp; i <= m; ++i) {
        if ((int)r[i].size() > 0) {
            if (os[i]) {
                tmp = (deter(i, 0) + deter(i, 1)) % mod;
            } else {
                tmp = deter(i, 0);
            }
            ways = 1ll * ways * tmp % mod;
            ans = 1ll * ans * inv[r[i].size()] % mod;
        }
    }
    ans = 1ll * ans * ways % mod;
    ans = 1ll * ans * fac[n + n] % mod;
    printf("%d\n", ans);
    return 0;
}

Measured memory_bytes: 101620