#include <bits/stdc++.h>
using namespace std;
const int maxn = 400555, mod = 1000000007, shif = maxn >> 1;
long long res = 1;
long long qpow(long long a, long long n) {
  long long res = 1;
  while (n) {
    if (n & 1) res = res * a % mod;
    a = a * a % mod;
    n >>= 1;
  }
  return res;
}
struct BitTree {
  long long a[maxn];
  bool f;
  inline int lowbit(int x) { return x & (-x); }
  void update(int x, long long val) {
    for (int i = x + shif; i < maxn; i += lowbit(i))
      if (f == 0)
        a[i] += val;
      else
        a[i] = a[i] * val % mod;
  }
  long long ask(int x) {
    long long res = (f ? 1 : 0);
    for (int i = x + shif; i > 0; i -= lowbit(i))
      if (f == 0)
        res = res + a[i];
      else
        res = res * a[i] % mod;
    return res;
  }
} m1, m2, c1, c2;
struct Node {
  int r, b;
  long long w;
  Node(int _r = 0, int _b = 0, long long _w = 1) : r(_r), b(_b), w(_w) {}
  Node operator+(const Node &nd) {
    return Node(r + nd.r, b + nd.b, w * nd.w % mod);
  }
} node[maxn];
vector<pair<int, Node> > e[maxn];
int root, Maxsz, sz[maxn], Max[maxn];
bool vis[maxn];
void dfsSize(int u, int par) {
  sz[u] = 1;
  Max[u] = 0;
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (v == par || vis[v]) continue;
    dfsSize(v, u);
    sz[u] += sz[v];
    Max[u] = max(Max[u], sz[v]);
  }
}
void dfsRoot(int u, int par, int tot) {
  Max[u] = max(Max[u], tot - sz[u]);
  if (Maxsz > Max[u]) {
    Maxsz = Max[u];
    root = u;
  }
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (vis[v] || v == par) continue;
    dfsRoot(v, u, tot);
  }
}
void getRoot(int trt) {
  Maxsz = maxn;
  dfsSize(trt, -1);
  dfsRoot(trt, -1, sz[trt]);
  vis[root] = 1;
}
void calc(int u, int par, Node x) {
  node[u] = node[par] + x;
  if (2 * min(node[u].r, node[u].b) >= max(node[u].b, node[u].r))
    res = res * node[u].w % mod;
  int A = 2 * node[u].r - node[u].b, B = node[u].r - 2 * node[u].b - 1;
  int n1 = c1.ask(A), n2 = c2.ask(B);
  if (n1 - n2 > 0)
    res = res * qpow(node[u].w, n1 - n2) % mod * m1.ask(A) % mod *
          qpow(m2.ask(B), mod - 2) % mod;
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (vis[v] || v == par) continue;
    calc(v, u, e[u][i].second);
  }
}
void update(int u, int par, bool f) {
  c1.update(node[u].b - 2 * node[u].r, f ? 1 : -1);
  c2.update(2 * node[u].b - node[u].r, f ? 1 : -1);
  m1.update(node[u].b - 2 * node[u].r,
            f ? node[u].w : qpow(node[u].w, mod - 2));
  m2.update(2 * node[u].b - node[u].r,
            f ? node[u].w : qpow(node[u].w, mod - 2));
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (v != par && !vis[v]) update(v, u, f);
  }
}
void solve(int r) {
  getRoot(r);
  int u = root;
  node[root] = Node(0, 0, 1);
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (!vis[v]) {
      calc(v, u, e[u][i].second);
      update(v, u, 1);
    }
  }
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (!vis[v]) update(v, u, 0);
  }
  for (int i = 0; i < ((int)e[u].size()); ++i) {
    int v = e[u][i].first;
    if (!vis[v]) solve(v);
  }
}
int main() {
  m1.f = m2.f = 1;
  int n;
  scanf("%d", &n);
  fill(m1.a, m1.a + maxn, 1);
  fill(m2.a, m2.a + maxn, 1);
  for (int i = 1; i < (n); ++i) {
    int a, b, w, c;
    scanf("%d %d %d %d", &a, &b, &w, &c);
    e[a].push_back(make_pair(b, Node(1 - c, c, w)));
    e[b].push_back(make_pair(a, Node(1 - c, c, w)));
  }
  solve(1);
  cout << res << endl;
}
