#include <bits/stdc++.h>
using namespace std;
template <class T>
T nextInt() {
  T x = 0, p = 1;
  char c;
  do {
    c = getchar();
  } while (c <= 32);
  if (c == '-') {
    p = -1;
    c = getchar();
  }
  while (c >= '0' && c <= '9') {
    x = x * 10 + c - '0';
    c = getchar();
  }
  return x * p;
}
const long long LINF = (long long)1e18;
const int INF = (int)1e9;
int P;
int add(int x, int y) {
  x += y;
  if (x >= P) x -= P;
  return x;
}
int mul(int x, int y) { return (1LL * x * y) % P; }
struct my {
  int val, idx;
  my() {}
  my(int val, int idx) : val(val), idx(idx) {}
};
int powmod(int x, int n) {
  int r = 1;
  while (n) {
    if ((n & 1)) {
      r = mul(r, x);
      --n;
    } else {
      x = mul(x, x);
      n >>= 1;
    }
  }
  return r;
}
const int maxN = 100500;
int n, k, x, val[maxN], in0[maxN], in1[maxN], out0[maxN], out1[maxN];
vector<int> g[maxN];
int revK[maxN];
int pwK[maxN];
void precalc() {
  revK[0] = 1;
  revK[1] = powmod(k, P - 2);
  pwK[0] = 1;
  pwK[1] = k;
  for (int i = 2; i < maxN; i++) {
    revK[i] = mul(revK[i - 1], revK[1]);
    pwK[i] = mul(pwK[i - 1], pwK[1]);
  }
}
int sz[maxN];
bool used[maxN];
void calcSz(int v, int p) {
  sz[v] = 1;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (to == p || used[to]) continue;
    calcSz(to, v);
    sz[v] += sz[to];
  }
}
int findCentroid(int v, int p, int N) {
  bool ok = true;
  if (N - sz[v] > N / 2) ok = false;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (to == p || used[to]) continue;
    int z = findCentroid(to, v, N);
    if (z != -1) return z;
    if (sz[to] > N / 2) ok = false;
  }
  return (ok ? v : -1);
}
void addValues(int v, int p, int curVal, int depth,
               vector<pair<int, int> >& s) {
  curVal = add(curVal, mul(val[v], pwK[depth]));
  s.push_back(make_pair(curVal, v));
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (to == p || used[to]) continue;
    addValues(to, v, curVal, depth + 1, s);
  }
}
void brutePaths(int v, int p, int curVal, int len, map<int, int>& s,
                map<int, int>& t) {
  curVal = add(mul(curVal, k), val[v]);
  int need = mul(add(x, P - curVal), revK[len]);
  in0[v] += s[need];
  t[need]++;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (to == p || used[to]) continue;
    brutePaths(to, v, curVal, len + 1, s, t);
  }
}
void pathsFromRoot(int v, int p, int val1, int val2, int depth, int root) {
  val1 = add(mul(val1, k), val[v]);
  val2 = add(val2, mul(val[v], pwK[depth]));
  if (val1 == x) out0[root]++, in0[v]++;
  if (v != root && val2 == x) out0[v]++, in0[root]++;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (to == p || used[to]) continue;
    pathsFromRoot(to, v, val1, val2, depth + 1, root);
  }
}
void processLayer(int v) {
  vector<int> child;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (used[to]) continue;
    child.push_back(to);
  }
  vector<vector<pair<int, int> > > values(child.size());
  map<int, int> s;
  map<int, int> t;
  for (size_t i = 0; i < child.size(); i++) {
    addValues(child[i], v, val[v], 1, values[i]);
    for (size_t it = 0; it < values[i].size(); it++) {
      s[values[i][it].first]++;
    }
  }
  for (size_t i = 0; i < child.size(); i++) {
    for (size_t it = 0; it < values[i].size(); it++) {
      s[values[i][it].first]--;
    }
    map<int, int> tmp;
    brutePaths(child[i], v, 0, 1, s, tmp);
    for (size_t it = 0; it < values[i].size(); it++) {
      s[values[i][it].first]++;
    }
    for (size_t it = 0; it < values[i].size(); it++) {
      out0[values[i][it].second] -= tmp[values[i][it].first];
    }
    for (map<int, int>::iterator it = tmp.begin(); it != tmp.end(); it++) {
      t[it->first] += it->second;
    }
  }
  for (size_t i = 0; i < child.size(); i++) {
    for (size_t j = 0; j < values[i].size(); j++) {
      out0[values[i][j].second] += t[values[i][j].first];
    }
  }
  pathsFromRoot(v, -1, 0, 0, 0, v);
}
void dfs(int v) {
  calcSz(v, -1);
  v = findCentroid(v, -1, sz[v]);
  processLayer(v);
  used[v] = true;
  for (size_t i = 0; i < g[v].size(); i++) {
    int to = g[v][i];
    if (used[to]) continue;
    dfs(to);
  }
}
void calcInOut() {
  dfs(1);
  for (int i = 1; i <= n; i++) {
    in1[i] = n - in0[i];
    out1[i] = n - out0[i];
  }
}
int main() {
  srand(time(0));
  n = nextInt<int>();
  P = nextInt<int>();
  k = nextInt<int>();
  x = nextInt<int>();
  precalc();
  for (int i = 1; i <= n; i++) {
    val[i] = nextInt<int>();
  }
  for (int i = 1; i <= n - 1; i++) {
    int x = nextInt<int>();
    int y = nextInt<int>();
    g[x].push_back(y);
    g[y].push_back(x);
  }
  calcInOut();
  long long tmp = 0;
  for (int i = 1; i <= n; i++) {
    tmp += (1LL * in0[i] * out1[i] + 1LL * in1[i] * out0[i] +
            2LL * in1[i] * in0[i] + 2LL * out1[i] * out0[i]);
  }
  long long result = 1LL * n * n * n - tmp / 2;
  cout << result << "\n";
}
