#include <bits/stdc++.h>
using namespace std;
const int lhh = 1000000007, maxn = 200010;
int nxt[maxn], toit[maxn], side[maxn], cnt, N;
int best, large[maxn], size[maxn];
bool vis[maxn], col[maxn];
long long len[maxn], ans = 1, pro1[maxn << 1], pro2[maxn << 1];
int sum1[maxn << 1], sum2[maxn << 1];
template <class T1>
inline void reset(T1 tree[], int a, int key) {
  for (; a <= (N << 2); a += (a & -a)) tree[a] = key;
}
inline void mul(long long tree[], int a, long long b) {
  for (; a <= (N << 2); a += (a & -a)) (tree[a] *= b) %= lhh;
}
inline void add(int tree[], int a, int b) {
  for (; a <= (N << 2); a += (a & -a)) tree[a] += b;
}
inline long long calc1(long long tree[], int a) {
  long long ret = 1;
  for (; a; a -= (a & -a)) (ret *= tree[a]) %= lhh;
  return ret;
}
inline int calc2(int tree[], int a) {
  int ret = 0;
  for (; a; a -= (a & -a)) ret += tree[a];
  return ret;
}
struct Node {
  long long mul;
  int a, b;
  inline Node(long long _mul = 1, int _a = 0, int _b = 0)
      : mul(_mul), a(_a), b(_b) {}
  inline Node(long long _mul, bool sgn) : mul(_mul), a(0), b(0) {
    if (!sgn)
      a = 1;
    else
      b = 1;
  }
  inline int calc1() { return a - (b << 1); }
  inline int calc2() { return b - (a << 1); }
  friend inline Node operator+(const Node &x, const Node &y) {
    return Node(x.mul * y.mul % lhh, x.a + y.a, x.b + y.b);
  }
};
vector<Node> vec;
inline void add(int a, int b, int c, int d) {
  nxt[++cnt] = side[a];
  side[a] = cnt;
  toit[cnt] = b;
  len[cnt] = c;
  col[cnt] = d;
}
inline void ins(int a, int b, int c, int d) {
  add(a, b, c, d);
  add(b, a, c, d);
}
inline long long qsm(long long a, long long b) {
  long long ret = 1;
  for (; b; b >>= 1, (a *= a) %= lhh)
    if (b & 1) (ret *= a) %= lhh;
  return ret;
}
inline int gi() {
  char ch;
  int ret = 0, f = 1;
  do ch = getchar();
  while (!(ch >= '0' && ch <= '9') && ch != '-');
  if (ch == '-') f = -1, ch = getchar();
  do ret = ret * 10 + ch - '0', ch = getchar();
  while (ch >= '0' && ch <= '9');
  return ret * f;
}
inline void getroot(int now, int fa, int rest) {
  size[now] = 1;
  large[now] = 0;
  for (int i = side[now]; i; i = nxt[i]) {
    if (toit[i] == fa || vis[toit[i]]) continue;
    getroot(toit[i], now, rest);
    size[now] += size[toit[i]];
    large[now] = max(large[now], size[toit[i]]);
    if (rest == N)
      (ans *= qsm(len[i], (long long)size[toit[i]] * (N - size[toit[i]]))) %=
          lhh;
  }
  large[now] = max(large[now], rest - size[now]);
  if (large[now] < large[best]) best = now;
}
inline int find_root(int now, int rest) {
  best = 0;
  getroot(now, 0, rest);
  return best;
}
inline void dfs(int now, int fa, const Node &sta) {
  vec.push_back(sta);
  size[now] = 1;
  for (int i = side[now]; i; i = nxt[i])
    if (toit[i] != fa && !vis[toit[i]])
      dfs(toit[i], now, sta + Node(len[i], col[i])), size[now] += size[toit[i]];
}
inline void cut(int now) {
  vis[now] = true;
  vector<Node> save;
  for (int i = side[now]; i; i = nxt[i]) {
    if (vis[toit[i]]) continue;
    vec.clear();
    dfs(toit[i], now, Node(len[i], col[i]));
    for (auto x : vec) {
      int p1 = x.calc1(), p2 = x.calc2();
      int n1 = calc2(sum1, p1 + (N << 1) - 1),
          n2 = calc2(sum2, p2 + (N << 1) - 1);
      long long res1 = qsm(x.mul, n1) * calc1(pro1, p1 + (N << 1) - 1) % lhh;
      long long res2 = qsm(x.mul, n2) * calc1(pro2, p2 + (N << 1) - 1) % lhh;
      (ans *= qsm((res1 * res2) % lhh, lhh - 2)) %= lhh;
      if (x.a > (x.b << 1) || x.b > (x.a << 1))
        (ans *= qsm(x.mul, lhh - 2)) %= lhh;
    }
    for (auto x : vec) {
      int p1 = -x.calc1() + (N << 1), p2 = -x.calc2() + (N << 1);
      add(sum1, p1, 1);
      mul(pro1, p1, x.mul);
      add(sum2, p2, 1);
      mul(pro2, p2, x.mul);
      save.push_back(x);
    }
  }
  for (auto x : save) {
    int p1 = -x.calc1() + (N << 1), p2 = -x.calc2() + (N << 1);
    reset(sum1, p1, 0);
    reset(pro1, p1, 1);
    reset(sum2, p2, 0);
    reset(pro2, p2, 1);
  }
  for (int i = side[now]; i; i = nxt[i])
    if (!vis[toit[i]]) cut(find_root(toit[i], size[toit[i]]));
}
int main() {
  N = gi();
  ans = 1;
  for (int i = 1; i <= (N << 2); ++i) pro1[i] = pro2[i] = 1;
  for (int i = 1, a, b, c, d; i < N; ++i)
    a = gi(), b = gi(), c = gi(), d = gi(), ins(a, b, c, d);
  large[0] = 1 << 30;
  cut(find_root(1, N));
  cout << ans << endl;
  return 0;
}
