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 maxn = 150005;
const int mlog = 20;
int n, m, k, t;
vector<int> edge[maxn], vec[maxn];
vector<pair<int, int> > path[maxn][mlog];
int sz[maxn], rt[maxn], dep[maxn], par[maxn][mlog], dfnL[maxn], dfnR[maxn],
    bel[maxn], val[maxn];
bool del[maxn];
long long ans1, ans2;
namespace Segtree {
const int maxv = maxn * mlog * 2;
int tot;
int ls[maxv], rs[maxv], sum[maxv];
void clear() {
  for (int i = 1; i <= tot; i++) ls[i] = rs[i] = sum[i] = 0;
  tot = 0;
}
void insert(int &cur, int l, int r, int k) {
  if (!cur) cur = ++tot;
  sum[cur]++;
  if (l == r) return;
  int mid = l + r >> 1;
  if (k <= mid)
    insert(ls[cur], l, mid, k);
  else
    insert(rs[cur], mid + 1, r, k);
}
int query(int cur, int l, int r, int vl, int vr) {
  if (!cur) return 0;
  if (l >= vl && r <= vr) return sum[cur];
  int mid = l + r >> 1;
  int sl = mid >= vl ? query(ls[cur], l, mid, vl, vr) : 0;
  int sr = mid < vr ? query(rs[cur], mid + 1, r, vl, vr) : 0;
  return sl + sr;
}
int merge(int cur1, int cur2, int l, int r) {
  if (!cur1 || !cur2) return cur1 ^ cur2;
  if (l == r) {
    sum[cur1] += sum[cur2];
    return cur1;
  }
  int mid = l + r >> 1;
  ls[cur1] = merge(ls[cur1], ls[cur2], l, mid);
  rs[cur1] = merge(rs[cur1], rs[cur2], mid + 1, r);
  sum[cur1] = sum[ls[cur1]] + sum[rs[cur1]];
  return cur1;
}
}  // namespace Segtree
int getpar(int x, int d) {
  for (int i = 0; i < mlog; i++)
    if ((d >> i) & 1) x = par[x][i];
  return x;
}
int lca(int x, int y) {
  if (dep[x] < dep[y]) swap(x, y);
  for (int i = mlog - 1; i >= 0; i--)
    if (par[x][i] && dep[par[x][i]] >= dep[y]) x = par[x][i];
  if (x == y) return x;
  for (int i = mlog - 1; i >= 0; i--)
    if (par[x][i] != par[y][i]) x = par[x][i], y = par[y][i];
  return par[x][0];
}
void dfs_sz(int x, int p) {
  sz[x] = 1;
  for (int i = 0; i < int(edge[x].size()); i++) {
    int y = edge[x][i];
    if (y == p || del[y]) continue;
    dfs_sz(y, x);
    sz[x] += sz[y];
  }
}
pair<int, int> dfs_rt(int x, int p, int t) {
  int mx = t - sz[x];
  pair<int, int> mn = make_pair(n, 0);
  for (int i = 0; i < int(edge[x].size()); i++) {
    int y = edge[x][i];
    if (y == p || del[y]) continue;
    mn = min(mn, dfs_rt(y, x, t));
    mx = max(mx, sz[y]);
  }
  mn = min(mn, make_pair(mx, x));
  return mn;
}
void dfs_inf(int x, int p, int d, int b) {
  dep[x] = d;
  bel[x] = b;
  par[x][0] = p;
  for (int i = 1; i < mlog; i++) par[x][i] = par[par[x][i - 1]][i - 1];
  vec[x].clear();
  rt[x] = 0;
  dfnL[x] = ++t;
  for (int i = 0; i < int(edge[x].size()); i++) {
    int y = edge[x][i];
    if (y == p || del[y]) continue;
    dfs_inf(y, x, d + 1, d == 0 ? y : b);
  }
  dfnR[x] = t;
}
void calc(int x, int u) {
  int cd = max(0, k - dep[x]);
  if (dep[u] < cd) return;
  if (cd == 0) {
    ans1 += Segtree::query(rt[x], 1, t, 1, t);
    if (dep[u] > 0)
      ans2 += Segtree::query(rt[x], 1, t, dfnL[bel[u]], dfnR[bel[u]]);
  } else {
    int v = getpar(u, dep[u] - cd);
    int csum = Segtree::query(rt[x], 1, t, dfnL[v], dfnR[v]);
    ans1 += csum;
    ans2 += csum;
  }
}
void add(int x, int u) {
  Segtree::insert(rt[x], 1, t, dfnL[u]);
  vec[x].push_back(u);
}
void dfs_work(int x, int p) {
  for (int i = 0; i < int(edge[x].size()); i++) {
    int y = edge[x][i];
    if (y == p || del[y]) continue;
    dfs_work(y, x);
    if (int(vec[y].size()) > int(vec[x].size()))
      swap(vec[x], vec[y]), swap(rt[x], rt[y]);
    for (int j = 0; j < int(vec[y].size()); j++)
      calc(x, vec[y][j]), vec[x].push_back(vec[y][j]);
    rt[x] = Segtree::merge(rt[x], rt[y], 1, t);
  }
}
void solve(int x, int lv) {
  if (path[x][lv].empty()) return;
  dfs_sz(x, 0);
  int rt = dfs_rt(x, 0, sz[x]).second;
  t = 0;
  dfs_inf(rt, 0, 0, rt);
  for (int i = 1; i <= t; i++) val[i] = 0;
  for (int i = 0; i < int(path[x][lv].size()); i++) {
    int u = path[x][lv][i].first, v = path[x][lv][i].second;
    if (bel[u] == bel[v]) {
      path[bel[u]][lv + 1].push_back(make_pair(u, v));
      int w = lca(u, v);
      if (dep[u] - dep[w] >= k) {
        int p = getpar(u, dep[u] - dep[w] - k);
        val[dfnL[p]]++;
        val[dfnR[p] + 1]--;
      }
      if (dep[v] - dep[w] >= k) {
        int p = getpar(v, dep[v] - dep[w] - k);
        val[dfnL[p]]++;
        val[dfnR[p] + 1]--;
      }
    }
  }
  for (int i = 1; i <= t; i++) val[i] += val[i - 1];
  Segtree::clear();
  for (int i = 0; i < int(path[x][lv].size()); i++) {
    int u = path[x][lv][i].first, v = path[x][lv][i].second;
    if (bel[u] != bel[v]) {
      if (u != rt) calc(u, v), add(u, v);
      if (v != rt) calc(v, u), add(v, u);
      ans1 += val[dfnL[u]] + val[dfnL[v]];
    }
  }
  for (int i = 0; i < int(edge[rt].size()); i++) {
    int y = edge[rt][i];
    if (del[y]) continue;
    dfs_work(y, rt);
  }
  del[rt] = true;
  for (int i = 0; i < int(edge[rt].size()); i++) {
    int y = edge[rt][i];
    if (del[y]) continue;
    solve(y, lv + 1);
  }
}
int main() {
  scanf("%d%d%d", &n, &m, &k);
  for (int i = 1; i <= n - 1; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    edge[u].push_back(v);
    edge[v].push_back(u);
  }
  while (m--) {
    int u, v;
    scanf("%d%d", &u, &v);
    path[1][0].push_back(make_pair(u, v));
  }
  solve(1, 0);
  printf("%lld\n", ans1 - ans2 / 2);
  return 0;
}
