30 30 10
6 1
8 27
5 1
21 6
24 15
12 5
29 7
22 7
23 17
2 13
23 11
29 6
14 18
29 16
27 25
15 2
27 4
19 30
28 19
17 2
27 16
3 4
9 25
19 16
10 16
18 17
26 11
2 27
16 20
13 23
1 4
27 7
6 20
17 30
1 18
2 17
1 11
5 9
25 13
11 20
14 25
30 21
6 24
12 2
25 12
22 13
10 27
24 29
19 24
28 29
24 23
9 6
12 15
11 15
23 14
12 28
28 25
2 11
19 30
 2 2 1
1 2
2 1
1 2

0 1
#include <bits/stdc++.h>
using namespace std;
const int N = 150005, M = 150005, LOG = 21;
template <class T>
void read(T &x) {
  int sgn = 1;
  char ch;
  x = 0;
  for (ch = getchar(); (ch < '0' || ch > '9') && ch != '-'; ch = getchar())
    ;
  if (ch == '-') ch = getchar(), sgn = -1;
  for (; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
  x *= sgn;
}
template <class T>
void write(T x) {
  if (x < 0)
    putchar('-'), write(-x);
  else if (x < 10)
    putchar(x + '0');
  else
    write(x / 10), putchar(x % 10 + '0');
}
struct edge {
  int to, nxt;
} tree[N << 1];
int n, m, k, s[M], t[M], w[M], head[N], cnt = 0;
void addedge(int u, int v) {
  edge e = {v, head[u]};
  tree[head[u] = cnt++] = e;
}
int euler[N << 1], id[N], dep[N << 1], Log2[N << 1], rmq[N << 1][LOG], tot = 0;
void dfs1(int u, int fa) {
  id[u] = tot, euler[tot++] = u;
  for (int i = head[u]; ~i; i = tree[i].nxt) {
    int v = tree[i].to;
    if (v != fa) {
      dep[v] = dep[u] + 1;
      dfs1(v, u);
      euler[tot++] = u;
    }
  }
}
void init() {
  Log2[1] = 0;
  for (int i = 2; i <= tot; i++) Log2[i] = Log2[i >> 1] + 1;
  for (int i = 0; i < tot; i++) rmq[i][0] = euler[i];
  for (int i = 0; i < tot; i++) {
    for (int j = 1; (1 << j) <= i + 1; j++) {
      if (dep[rmq[i][j - 1]] <= dep[rmq[i - (1 << (j - 1))][j - 1]])
        rmq[i][j] = rmq[i][j - 1];
      else
        rmq[i][j] = rmq[i - (1 << (j - 1))][j - 1];
    }
  }
}
int lca(int u, int v) {
  int l = id[u], r = id[v];
  if (l > r) swap(l, r);
  int label = Log2[r - l + 1];
  if (dep[rmq[r][label]] <= dep[rmq[l + (1 << label) - 1][label]])
    return rmq[r][label];
  else
    return rmq[l + (1 << label) - 1][label];
}
long long ans = 0ll;
int key[M << 1], sz[M << 1], ch1[M << 1][2], rt1[N];
vector<int> vec[N];
int merge1(int u, int v) {
  if (!u) return v;
  if (!v) return u;
  if (key[u] < key[v]) swap(u, v);
  ch1[u][1] = merge1(ch1[u][1], v);
  swap(ch1[u][0], ch1[u][1]);
  sz[u] = sz[ch1[u][0]] + sz[ch1[u][1]] + 1;
  return u;
}
int pop(int u) { return merge1(ch1[u][0], ch1[u][1]); }
void dfs2(int u, int fa) {
  rt1[u] = 0;
  for (int i = 0; i < vec[u].size(); i++) {
    if (dep[w[vec[u][i] >> 1]] <= dep[u] - k) {
      ans += sz[rt1[u]], rt1[u] = merge1(rt1[u], vec[u][i]);
    }
  }
  for (int i = head[u]; ~i; i = tree[i].nxt) {
    int v = tree[i].to;
    if (v != fa) {
      dfs2(v, u);
      while (rt1[v] && key[rt1[v]] > dep[u] - k) rt1[v] = pop(rt1[v]);
      ans += 1ll * sz[rt1[u]] * sz[rt1[v]], rt1[u] = merge1(rt1[u], rt1[v]);
    }
  }
}
vector<int> node_list[N], route_list[N], vtree[N];
int mn_dep[N << 3], stk[N], top = 0;
bool cmp(int u, int v) { return id[u] < id[v]; }
void build(int l, int r, int now) {
  int mid = l + r >> 1;
  if (l == r)
    mn_dep[now] = dep[euler[mid]];
  else {
    build(l, mid, now << 1), build(mid + 1, r, now << 1 | 1);
    mn_dep[now] = min(mn_dep[now << 1], mn_dep[now << 1 | 1]);
  }
}
int sgt[M * LOG * 2], ch2[M * LOG * 2][2], rt2[N], tim = 0;
int get_l(int l, int r, int now1, int now2, int val) {
  int mid = l + r >> 1;
  if (l == r)
    return mn_dep[now1] >= val ? sgt[now2] : 0;
  else if (mn_dep[now1 << 1 | 1] >= val)
    return get_l(l, mid, now1 << 1, ch2[now2][0], val) + sgt[ch2[now2][1]];
  else
    return get_l(mid + 1, r, now1 << 1 | 1, ch2[now2][1], val);
}
int get_r(int l, int r, int now1, int now2, int val) {
  int mid = l + r >> 1;
  if (l == r)
    return mn_dep[now1] >= val ? sgt[now2] : 0;
  else if (mn_dep[now1 << 1] >= val)
    return get_r(mid + 1, r, now1 << 1 | 1, ch2[now2][1], val) +
           sgt[ch2[now2][0]];
  else
    return get_r(l, mid, now1 << 1, ch2[now2][0], val);
}
struct info {
  int u;
  pair<int, int> pi, pi1, pi2;
};
pair<int, int> get_info(int l, int r, int now1, int now2, int val) {
  return make_pair(get_l(l, r, now1, now2, val), get_r(l, r, now1, now2, val));
}
int newsgt(int pos, int l, int r) {
  int rt = ++tim, mid = l + r >> 1;
  sgt[rt] = 1, ch2[rt][0] = ch2[rt][1] = 0;
  if (l < r) {
    if (pos <= mid)
      ch2[rt][0] = newsgt(pos, l, mid);
    else
      ch2[rt][1] = newsgt(pos, mid + 1, r);
  }
  return rt;
}
info merge2(int l, int r, int now, int u, int v, int val, int sgn) {
  info res;
  if (!u) {
    res.u = v, res.pi.second = sgt[v];
    if (v) res.pi2 = get_info(l, r, now, v, val);
    return res;
  }
  if (!v) {
    res.u = u, res.pi.first = sgt[u];
    if (u) res.pi1 = get_info(l, r, now, u, val);
    return res;
  }
  int mid = l + r >> 1;
  if (l < r) {
    info lch = merge2(l, mid, now << 1, ch2[u][0], ch2[v][0], val, sgn);
    info rch = merge2(mid + 1, r, now << 1 | 1, ch2[u][1], ch2[v][1], val, sgn);
    res.u = u;
    res.pi =
        make_pair(lch.pi.first + rch.pi.first, lch.pi.second + rch.pi.second);
    res.pi1.first = mn_dep[now << 1 | 1] >= val ? lch.pi1.first + rch.pi.first
                                                : rch.pi1.first;
    res.pi1.second = mn_dep[now << 1] >= val ? rch.pi1.second + lch.pi.first
                                             : lch.pi1.second;
    res.pi2.first = mn_dep[now << 1 | 1] >= val ? lch.pi2.first + rch.pi.second
                                                : rch.pi2.first;
    res.pi2.second = mn_dep[now << 1] >= val ? rch.pi2.second + lch.pi.second
                                             : lch.pi2.second;
    ch2[u][0] = lch.u, ch2[u][1] = rch.u, sgt[u] += sgt[v];
    ans += 1ll * sgn * lch.pi1.first * rch.pi2.second +
           1ll * sgn * lch.pi2.first * rch.pi1.second;
    return res;
  } else {
    if (mn_dep[now] >= val) {
      ans += 1ll * sgn * sgt[u] * sgt[v];
      res.pi1.first = res.pi1.second = sgt[u];
      res.pi2.first = res.pi2.second = sgt[v];
    }
    res.u = u, res.pi = make_pair(sgt[u], sgt[v]), sgt[u] += sgt[v];
    return res;
  }
}
void build_info(int rt) {
  node_list[rt].push_back(1);
  sort(node_list[rt].begin(), node_list[rt].end(), cmp),
      sgt[0] = ch2[0][0] = ch2[0][1] = 0;
  int tmp = unique(node_list[rt].begin(), node_list[rt].end()) -
            node_list[rt].begin();
  node_list[rt].resize(tmp);
  for (int i = 0; i < route_list[rt].size(); i++) {
    int j = route_list[rt][i];
    vec[s[j]].push_back(j << 1), vec[t[j]].push_back(j << 1 | 1);
  }
  vector<int> extend_list = node_list[rt];
  stk[top = 1] = 1;
  for (int i = 0; i < node_list[rt].size(); i++) {
    int u = node_list[rt][i], v = lca(u, stk[top]);
    while (top > 1 && id[stk[top - 1]] >= id[v]) {
      vtree[stk[top - 1]].push_back(stk[top]);
      top--;
    }
    if (stk[top] != v) vtree[v].push_back(stk[top]), stk[top] = v;
    if (v != u) stk[++top] = u;
    extend_list.push_back(v);
  }
  while (top > 1) vtree[stk[top - 1]].push_back(stk[top]), top--;
  node_list[rt] = extend_list;
}
int f[N];
void dfs3(int u, int rt) {
  rt2[u] = f[u] = 0;
  for (int i = 0; i < vec[u].size(); i++) {
    if (dep[u] - dep[rt] >= k) ans -= f[u]++;
    int v = vec[u][i] & 1 ? s[vec[u][i] >> 1] : t[vec[u][i] >> 1];
    if (u != rt)
      rt2[u] = merge2(0, tot - 1, 1, rt2[u], newsgt(id[v], 0, tot - 1),
                      k - dep[u] + dep[rt] * 2, 1)
                   .u;
  }
  for (int i = 0; i < vtree[u].size(); i++) {
    int v = vtree[u][i];
    dfs3(v, rt);
    if (dep[u] - dep[rt] >= k) ans -= 1ll * f[u] * f[v];
    f[u] += f[v];
    if (u != rt)
      rt2[u] =
          merge2(0, tot - 1, 1, rt2[u], rt2[v], k - dep[u] + dep[rt] * 2, 1).u;
  }
}
void dfs4(int u, int rt) {
  rt2[u] = 0;
  for (int i = 0; i < vec[u].size(); i++) {
    int v = vec[u][i] & 1 ? s[vec[u][i] >> 1] : t[vec[u][i] >> 1];
    if (u != rt && id[v] < id[u]) {
      rt2[u] = merge2(0, tot - 1, 1, rt2[u], newsgt(id[v], 0, tot - 1),
                      max(dep[rt] + 1, k - dep[u] + dep[rt] * 2), -1)
                   .u;
    }
  }
  for (int i = 0; i < vtree[u].size(); i++) {
    int v = vtree[u][i];
    dfs4(v, rt);
    if (u != rt)
      rt2[u] = merge2(0, tot - 1, 1, rt2[u], rt2[v],
                      max(dep[rt] + 1, k - dep[u] + dep[rt] * 2), -1)
                   .u;
  }
}
void clear_info(int rt) {
  for (int i = 0; i < node_list[rt].size(); i++) {
    int u = node_list[rt][i];
    vec[u].clear();
    vtree[u].clear();
  }
  route_list[rt].clear(), node_list[rt].clear();
}
int main() {
  read(n), read(m), read(k);
  for (int i = 1; i <= n; i++) head[i] = -1;
  for (int i = 1; i < n; i++) {
    int u, v;
    read(u), read(v);
    addedge(u, v), addedge(v, u);
  }
  for (int i = 1; i <= m; i++) {
    read(s[i]), read(t[i]);
    sz[i << 1] = sz[i << 1 | 1] = 1;
    ch1[i << 1][0] = ch1[i << 1][1] = 0;
    ch1[i << 1 | 1][0] = ch1[i << 1 | 1][1] = 0;
  }
  dep[1] = 0, dfs1(1, 0), init();
  for (int i = 1; i <= m; i++) {
    w[i] = lca(s[i], t[i]);
    key[i << 1] = key[i << 1 | 1] = dep[w[i]];
    vec[s[i]].push_back(i << 1);
    vec[t[i]].push_back(i << 1 | 1);
  }
  sz[0] = 0, dfs2(1, 0);
  for (int i = 1; i <= m; i++) {
    node_list[w[i]].push_back(s[i]);
    node_list[w[i]].push_back(t[i]);
    route_list[w[i]].push_back(i);
  }
  for (int i = 1; i <= n; i++) vec[i].clear();
  build(0, tot - 1, 1);
  for (int i = 1; i <= n; i++) {
    build_info(i);
    tim = 0, dfs3(i, i);
    tim = 0, dfs4(i, i);
    clear_info(i);
  }
  write(ans), putchar('\n');
  return 0;
}
