#include <bits/stdc++.h>
using namespace std;
inline const long long Get_Int() {
  long long num = 0, bj = 1;
  char x = getchar();
  while (x < '0' || x > '9') {
    if (x == '-') bj = -1;
    x = getchar();
  }
  while (x >= '0' && x <= '9') {
    num = num * 10 + x - '0';
    x = getchar();
  }
  return num * bj;
}
const int maxn = 100005;
int root, Size[maxn], Maxson[maxn], Min, Core, vst[maxn], Len[maxn];
long long n, mod, X, K, ans = 0, a[maxn], Val[maxn], inv[maxn], In[maxn],
                        Out[maxn], Dist1[maxn], Dist2[maxn];
vector<int> edges[maxn];
void AddEdge(int x, int y) { edges[x].push_back(y); }
void Get_Size(int Now, int father) {
  Size[Now] = 1;
  Maxson[Now] = 0;
  for (int Next : edges[Now]) {
    if (Next == father || vst[Next]) continue;
    Get_Size(Next, Now);
    Size[Now] += Size[Next];
    Maxson[Now] = max(Maxson[Now], Size[Next]);
  }
}
void Get_Core(int Now, int father, int num) {
  Maxson[Now] = max(Maxson[Now], Size[num] - Size[Now]);
  if (Maxson[Now] < Min) {
    Min = Maxson[Now];
    Core = Now;
  }
  for (int Next : edges[Now]) {
    if (Next == father || vst[Next]) continue;
    Get_Core(Next, Now, num);
  }
}
void TreeDp(int Now, int fa, int depth, long long in, long long out) {
  if (in == X) In[root]++, Out[Now] += fa != -1;
  if (out == X) Out[root]++, In[Now] += fa != -1;
  Dist1[Now] = in;
  Dist2[Now] = ((out - a[root]) % mod + mod) % mod;
  Len[Now] = depth;
  for (int Next : edges[Now]) {
    if (Next == fa || vst[Next]) continue;
    TreeDp(Next, Now, depth + 1, (in * K % mod + a[Next]) % mod,
           (out + a[Next] * Val[depth + 1] % mod) % mod);
  }
}
map<int, int> Hash1, Hash2;
void Get_Ans_1(int Now, int fa) {
  Out[Now] += Hash1[((X - Dist1[Now]) % mod + mod) % mod * inv[Len[Now]] % mod];
  for (int Next : edges[Now]) {
    if (Next == fa || vst[Next]) continue;
    Get_Ans_1(Next, Now);
  }
}
void Get_Ans_2(int Now, int fa) {
  In[Now] += Hash2[Dist2[Now]];
  for (int Next : edges[Now]) {
    if (Next == fa || vst[Next]) continue;
    Get_Ans_2(Next, Now);
  }
}
void Add_Out(int Now, int fa) {
  Hash1[Dist2[Now]]++;
  for (int Next : edges[Now]) {
    if (Next == fa || vst[Next]) continue;
    Add_Out(Next, Now);
  }
}
void Add_In(int Now, int fa) {
  Hash2[((X - Dist1[Now]) % mod + mod) % mod * inv[Len[Now]] % mod]++;
  for (int Next : edges[Now]) {
    if (Next == fa || vst[Next]) continue;
    Add_In(Next, Now);
  }
}
void Dfs(int Now) {
  Min = n;
  Get_Size(Now, 0);
  Get_Core(Now, 0, Now);
  root = Now = Core;
  vst[Now] = 1;
  Hash1.clear();
  Hash2.clear();
  TreeDp(Now, -1, 0, a[Now], a[Now]);
  for (int Next : edges[Now]) {
    if (vst[Next]) continue;
    Get_Ans_1(Next, -1);
    Get_Ans_2(Next, -1);
    Add_Out(Next, -1);
    Add_In(Next, -1);
  }
  Hash1.clear();
  Hash2.clear();
  for (vector<int>::reverse_iterator it = edges[Now].rbegin();
       it != edges[Now].rend(); it++) {
    int Next = *it;
    if (vst[Next]) continue;
    Get_Ans_1(Next, -1);
    Get_Ans_2(Next, -1);
    Add_Out(Next, -1);
    Add_In(Next, -1);
  }
  for (int Next : edges[Now]) {
    if (vst[Next]) continue;
    Dfs(Next);
  }
}
long long Quick_Pow(long long a, long long b) {
  long long ans = 1;
  while (b) {
    if (b & 1) ans = ans * a % mod;
    a = a * a % mod;
    b >>= 1;
  }
  return ans;
}
int main() {
  n = Get_Int();
  mod = Get_Int();
  K = Get_Int();
  X = Get_Int();
  for (int i = 1; i <= n; i++) a[i] = Get_Int();
  for (int i = 1; i < n; i++) {
    int x = Get_Int(), y = Get_Int();
    AddEdge(x, y);
    AddEdge(y, x);
  }
  Val[0] = 1;
  inv[0] = 1;
  for (int i = 1; i <= n; i++)
    Val[i] = Val[i - 1] * K % mod, inv[i] = Quick_Pow(Val[i], mod - 2);
  Dfs(1);
  for (int i = 1; i <= n; i++)
    ans += In[i] * (n - Out[i]) + (n - In[i]) * Out[i] +
           2 * (Out[i] * (n - Out[i]) + (n - In[i]) * In[i]);
  printf("%I64d\n", n * n * n - ans / 2);
  return 0;
}
