#include <bits/stdc++.h>
#pragma GCC optimize("O2,Ofast,inline,unroll-all-loops,-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,popcnt")
using namespace std;
int val[100010], sz[100010], in_true[100010], in_false[100010],
    out_true[100010], out_false[100010], root, root_max, n;
const int INF = 1 << 30;
long long bin[100010], inv[100010], a, b, p, ans = 0;
bool vis[100010];
vector<int> nxt[100010];
map<long long, int> cnt_in, cnt_out;
template <class T>
void read(T &x) {
  char ch = x = 0;
  bool fl = false;
  while (!isdigit(ch)) fl |= ch == '-', ch = getchar();
  while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
  x = fl ? -x : x;
}
long long pw(long long a, long long b) {
  long long ret = 1;
  while (b) {
    if (b & 1) ret = ret * a % p;
    a = a * a % p, b >>= 1;
  }
  return ret;
}
void get_root(int x, int fa, int sum) {
  int tmp_max = 0;
  sz[x] = 1;
  for (auto &v : nxt[x]) {
    if (vis[v] || v == fa) continue;
    get_root(v, x, sum), sz[x] += sz[v];
    tmp_max = max(tmp_max, sz[v]);
  }
  tmp_max = max(tmp_max, sum - sz[x]);
  if (tmp_max < root_max) root = x, root_max = tmp_max;
}
void dfs(int x, int fa, int dep, long long val_in, long long val_out,
         bool flag) {
  cnt_in[(b - val_in + p) * inv[dep] % p]++, cnt_out[val_out]++;
  if (flag) {
    in_true[x] += val_out == b, out_true[x] += val_in == b;
    in_true[root] += val_in == b, out_true[root] += val_out == b;
  }
  for (auto &v : nxt[x]) {
    if (vis[v] || v == fa) continue;
    dfs(v, x, dep + 1, (val_in * a + val[v]) % p,
        (val_out + bin[dep] * val[v]) % p, flag);
  }
}
void dfs_2(int x, int fa, int dep, long long val_in, long long val_out) {
  in_true[x] += cnt_in[val_in],
      out_true[x] += cnt_out[(b - val_out + p) * inv[dep] % p];
  for (auto &v : nxt[x]) {
    if (vis[v] || v == fa) continue;
    dfs_2(v, x, dep + 1, (val_in + bin[dep] * val[v]) % p,
          (val_out * a + val[v]) % p);
  }
}
void divide_conquer(int x, int sum) {
  root_max = INF, get_root(x, 0, sum);
  vis[root] = true;
  cnt_in.clear(), cnt_out.clear();
  for (auto &v : nxt[root]) {
    if (vis[v]) continue;
    dfs_2(v, root, 1, val[v], val[v]);
    dfs(v, root, 2, (val[root] * a + val[v]) % p, (val[root] + val[v] * a) % p,
        true);
  }
  reverse(nxt[root].begin(), nxt[root].end());
  cnt_in.clear(), cnt_out.clear();
  for (auto &v : nxt[root]) {
    if (vis[v]) continue;
    dfs_2(v, root, 1, val[v], val[v]);
    dfs(v, root, 2, (val[root] * a + val[v]) % p, (val[root] + val[v] * a) % p,
        false);
  }
  for (auto &v : nxt[root]) {
    if (!vis[v]) divide_conquer(v, sz[v]);
  }
}
void init() {
  for (int i = 0; i <= n; i++) {
    bin[i] = pw(a, i), inv[i] = pw(bin[i], p - 2);
  }
}
int main() {
  read(n), read(p), read(a), read(b), init();
  for (int i = 1; i <= n; i++) {
    read(val[i]), val[i] %= p;
  }
  for (int i = 1, u, v; i <= n - 1; i++) {
    read(u), read(v);
    nxt[u].push_back(v), nxt[v].push_back(u);
  }
  divide_conquer(1, n);
  for (int i = 1; i <= n; i++) {
    in_true[i] += val[i] == b, out_true[i] += val[i] == b;
    in_false[i] = n - in_true[i], out_false[i] = n - out_true[i];
    ans += 2LL * in_true[i] * in_false[i] + 2LL * out_true[i] * out_false[i] +
           1LL * in_true[i] * out_false[i] + 1LL * out_true[i] * in_false[i];
  }
  printf("%lld\n", 1LL * n * n * n - ans / 2);
  return 0;
}
