#include <bits/stdc++.h>
using std::inplace_merge;
using std::max;
using std::min;
using std::sort;
using std::swap;
template <typename T>
void read(T &x) {
  int flag = 1;
  x = 0;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') flag = -flag;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
  x *= flag;
}
const int N = 1e5 + 10, Mod = 1e9 + 7;
int qpow(int x, int y) {
  int ret = 1;
  while (y) {
    if (y & 1) ret = 1ll * ret * x % Mod;
    x = 1ll * x * x % Mod, y >>= 1;
  }
  return ret;
}
struct Point {
  int x, y, op, v;
};
bool operator<(const Point &l, const Point &r) {
  return (l.x < r.x) || (l.x == r.x && l.y < r.y);
}
struct Edge {
  int to, cost, col, nxt;
} e[N << 1];
int from[N], e_num;
void addEdge(int u, int v, int w, int c) {
  e[++e_num] = (Edge){v, w, c, from[u]}, from[u] = e_num;
}
int n, ans = 1, siz[N];
bool vis[N];
int g, Size, rmx, c1[N << 2], c2[N << 2];
Point stk[N], q[N << 2];
int top, cnt;
inline int lb(int x) { return x & -x; }
void add(int x, int v) {
  while (x <= n * 4 + 1) c1[x] = 1ll * c1[x] * v % Mod, c2[x]++, x += lb(x);
}
int Sum(int x) {
  int ret = 1;
  while (x) ret = 1ll * c1[x] * ret % Mod, x -= lb(x);
  return ret;
}
int Cnt(int x) {
  int ret = 0;
  while (x) ret += c2[x], x -= lb(x);
  return ret;
}
void Set(int x) {
  while (x <= n * 4 + 1) c1[x] = 1, c2[x] = 0, x += lb(x);
}
void getrt(int x, int f) {
  siz[x] = 1;
  int mx = 0;
  for (int i = from[x]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (v == f || vis[v]) continue;
    getrt(v, x);
    siz[x] += siz[v];
    mx = max(mx, siz[v]);
  }
  mx = max(mx, Size - siz[x]);
  if (mx < rmx) rmx = mx, g = x;
}
void getpoi(int x, int f, int R, int B, int val) {
  stk[++top] = (Point){R, B, 0, val};
  for (int i = from[x]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (v == f || vis[v]) continue;
    if (!e[i].col)
      getpoi(v, x, R + 1, B, 1ll * val * e[i].cost % Mod);
    else if (e[i].col == 1)
      getpoi(v, x, R, B + 1, 1ll * val * e[i].cost % Mod);
  }
}
void cdq(int l, int r) {
  if (l >= r) return;
  int mid = (l + r) >> 1;
  cdq(l, mid), cdq(mid + 1, r);
  int j = l;
  for (int i = mid + 1; i <= r; ++i) {
    if (!q[i].op) continue;
    while (q[j].x <= q[i].x && j <= mid) {
      if (!q[j].op) add(q[j].y, q[j].v);
      ++j;
    }
    ans = 1ll * ans * Sum(q[i].y) % Mod * qpow(q[i].v, Cnt(q[i].y)) % Mod;
  }
  for (int i = l; i < j; ++i)
    if (!q[i].op) Set(q[i].y);
  inplace_merge(&q[l], &q[mid + 1], &q[r + 1]);
}
void doit(int x) {
  vis[x] = 1, cnt = 0;
  int Pls = 2 * n + 1;
  for (int i = from[x]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (vis[v]) continue;
    top = 0;
    if (!e[i].col)
      getpoi(v, x, 1, 0, e[i].cost);
    else if (e[i].col == 1)
      getpoi(v, x, 0, 1, e[i].cost);
    for (int j = 1; j <= top; ++j) {
      int a = stk[j].x, b = stk[j].y;
      q[++cnt] = (Point){2 * a - b + Pls, 2 * b - a + Pls, 1, stk[j].v};
    }
    for (int j = 1; j <= top; ++j) {
      int a = stk[j].x, b = stk[j].y;
      q[++cnt] = (Point){b - 2 * a + Pls, a - 2 * b + Pls, 0, stk[j].v};
      if (2 * min(a, b) >= max(a, b)) ans = 1ll * ans * stk[j].v % Mod;
    }
  }
  cdq(1, cnt);
  for (int i = from[x]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (vis[v]) continue;
    Size = rmx = siz[v];
    getrt(v, x), doit(g);
  }
}
int main() {
  read(n);
  for (int i = 1, u, v, w, c; i < n; ++i) {
    read(u), read(v), read(w), read(c);
    addEdge(u, v, w, c), addEdge(v, u, w, c);
  }
  for (int i = 1; i <= n * 4 + 1; ++i) c1[i] = 1, c2[i] = 0;
  Size = rmx = n;
  getrt(1, 0), doit(g);
  printf("%d\n", ans);
  return 0;
}
