#include <bits/stdc++.h>
const int max_N = 150343;
int n, m, K, dfn[max_N], Idfn[max_N], size[max_N], dep[max_N], fa[max_N],
    son[max_N], top[max_N];
std::vector<int> T[max_N];
long long ans;
int read() {
  char c = getchar();
  int ans = 0;
  bool flag = true;
  while (!isdigit(c)) flag &= (c != '-'), c = getchar();
  while (isdigit(c)) ans = 10 * ans + c - '0', c = getchar();
  return flag ? ans : -ans;
}
void Write(long long x) {
  if (x < 0) putchar('-'), x = -x;
  if (x < 10)
    putchar(x + '0');
  else
    Write(x / 10), putchar(x % 10 + '0');
}
struct path {
  int u, v, lca;
} P[max_N];
int min(int x, int y) { return x < y ? x : y; }
int max(int x, int y) { return x > y ? x : y; }
void _min(int &x, int y) {
  if (x > y) x = y;
}
void _max(int &x, int y) {
  if (x < y) x = y;
}
long long C2(int x) { return x * (x - 1ll) / 2; }
void dfs1(int x) {
  size[x] = 1, dep[x] = dep[fa[x]] + 1;
  for (auto i : T[x]) {
    if (i == fa[x]) continue;
    fa[i] = x, dfs1(i), size[x] += size[i];
    if (size[i] > size[son[x]]) son[x] = i;
  }
}
void dfs2(int x, int _top = 1) {
  Idfn[dfn[x] = ++*dfn] = x, top[x] = _top;
  if (!son[x]) return;
  dfs2(son[x], _top);
  for (auto i : T[x])
    if (i != fa[x] && i != son[x]) dfs2(i, i);
}
int LCA(int x, int y) {
  while (top[x] != top[y])
    dep[top[x]] < dep[top[y]] ? y = fa[top[y]] : x = fa[top[x]];
  return dep[x] < dep[y] ? x : y;
}
int dist(int x, int y) { return dep[x] + dep[y] - 2 * dep[LCA(x, y)]; }
int kth(int x, int k) {
  k = dep[x] - k;
  while (dep[top[x]] > k) x = fa[top[x]];
  return Idfn[dfn[x] - (dep[x] - k)];
}
namespace work1 {
int buc[max_N], X[max_N], Y[max_N];
std::vector<std::pair<int, int> > ms, qs;
namespace BIT {
int A[max_N], n;
void init(int _n) { n = _n, std::fill(A + 1, A + n + 1, 0); }
void modify(int x, int y) {
  while (x <= n) A[x] += y, x += (x & -x);
}
int query(int x) {
  int ans = 0;
  while (x) ans += A[x], x &= (x - 1);
  return ans;
}
}  // namespace BIT
void solve() {
  BIT::init(n);
  for (int i = 1; i <= n; i++)
    if (dep[i] > K)
      qs.emplace_back(dfn[i] - 1, i), qs.emplace_back(dfn[i] + size[i] - 1, i);
  for (int i = 1; i <= m; i++) {
    if (P[i].u != P[i].lca) ms.emplace_back(dfn[P[i].u], dep[P[i].lca]);
    if (P[i].v != P[i].lca) ms.emplace_back(dfn[P[i].v], dep[P[i].lca]);
  }
  std::sort(ms.begin(), ms.end()), std::sort(qs.begin(), qs.end());
  for (int i = 0, j = 0; i < qs.size(); i++) {
    while (j < ms.size() && ms[j].first <= qs[i].first)
      BIT::modify(ms[j].second, 1), buc[ms[j].second]++, j++;
    if (qs[i].first == dfn[qs[i].second] - 1)
      X[qs[i].second] -= BIT::query(dep[qs[i].second] - K - 1),
          Y[qs[i].second] -= buc[dep[qs[i].second] - K];
    else
      X[qs[i].second] += BIT::query(dep[qs[i].second] - K - 1),
          Y[qs[i].second] += buc[dep[qs[i].second] - K];
  }
  for (int i = 1; i <= n; i++) ans += (long long)X[i] * Y[i];
}
}  // namespace work1
namespace work2 {
std::vector<int> vec[max_N];
void solve() {
  for (int i = 1; i <= m; i++) {
    int u = P[i].u, v = P[i].v, lca = P[i].lca;
    int bu = (u == lca ? -1 : kth(u, dep[u] - dep[lca] - 1));
    int bv = (v == lca ? -1 : kth(v, dep[v] - dep[lca] - 1));
    if (dep[u] - dep[lca] >= K)
      vec[kth(u, dep[u] - dep[lca] - K)].push_back(bv);
    if (dep[v] - dep[lca] >= K)
      vec[kth(v, dep[v] - dep[lca] - K)].push_back(bu);
  }
  for (int i = 1; i <= n; i++) {
    std::sort(vec[i].begin(), vec[i].end());
    ans += C2(vec[i].size());
    for (int l = 0, r = 0; l < vec[i].size(); l = r) {
      while (r < vec[i].size() && vec[i][l] == vec[i][r]) r++;
      if (vec[i][l] != -1) ans -= C2(r - l);
    }
  }
}
}  // namespace work2
namespace work3 {
namespace ST {
int root[max_N], sum[max_N * 20], lson[max_N * 20], rson[max_N * 20], cnt;
std::vector<int> vis;
void init() {
  std::fill(sum + 1, sum + cnt + 1, 0);
  std::fill(lson + 1, lson + cnt + 1, 0);
  std::fill(rson + 1, rson + cnt + 1, 0);
  for (auto i : vis) root[i] = 0;
  vis.clear();
  cnt = 0;
}
void Insert(int L, int R, int x, int &rt) {
  if (!rt) rt = ++cnt;
  sum[rt]++;
  if (L < R)
    ((L + R) / 2) >= x ? Insert(L, ((L + R) / 2), x, lson[rt])
                       : Insert(((L + R) / 2) + 1, R, x, rson[rt]);
}
void Insert(int x, int y) { vis.push_back(x), Insert(1, n, y, root[x]); }
int query(int L, int R, int l, int r, int rt) {
  if (!rt) return 0;
  if (l <= L && R <= r) return sum[rt];
  if (((L + R) / 2) < l) return query(((L + R) / 2) + 1, R, l, r, rson[rt]);
  if (((L + R) / 2) >= r) return query(L, ((L + R) / 2), l, r, lson[rt]);
  return query(L, ((L + R) / 2), l, r, lson[rt]) +
         query(((L + R) / 2) + 1, R, l, r, rson[rt]);
}
int query(int x, int l, int r) { return query(1, n, l, r, root[x]); }
int merge(int l, int x, int y) {
  if (!x || !y) return x | y;
  sum[x] += sum[y];
  if (l > 1)
    lson[x] = merge((l + 1) / 2, lson[x], lson[y]),
    rson[x] = merge(l / 2, rson[x], rson[y]);
  return x;
}
int merge(int x, int y) {
  return vis.push_back(x), root[x] = merge(n, root[x], root[y]);
}
}  // namespace ST
namespace virtual_tree {
int nxt[max_N], head[max_N], to[max_N], stack[max_N], id[max_N], top, tot, rt;
std::vector<int> V, vis, vec[max_N];
std::multiset<int> P[max_N];
void add_edge(int u, int v) {
  nxt[++tot] = head[u], head[u] = tot, to[tot] = v;
}
void init() {
  for (auto i : vis) head[i] = 0, P[i].clear(), vec[i].clear();
  std::sort(V.begin(), V.end(), [&](int x, int y) { return dfn[x] < dfn[y]; });
  V.resize(std::unique(V.begin(), V.end()) - V.begin());
  tot = top = 0, vis = V;
}
void build(std::vector<int> &_V) {
  V = _V;
  init();
  stack[++top] = V[0];
  for (int i = 1; i < V.size(); i++) {
    int lca = LCA(stack[top], V[i]);
    vis.push_back(lca);
    while (top > 1 && dep[stack[top - 1]] >= dep[lca])
      add_edge(stack[top - 1], stack[top]), top--;
    if (dep[stack[top]] > dep[lca]) add_edge(lca, stack[top]), top--;
    if (stack[top] != lca) stack[++top] = lca;
    stack[++top] = V[i];
  }
  while (top > 1) add_edge(stack[top - 1], stack[top]), top--;
  rt = stack[top];
}
int calc(int lca, int x, int y) {
  if (dep[lca] + dep[y] - 2 * dep[rt] < K) return 0;
  int p =
      kth(y, min(dep[y] - dep[rt] - 1, dep[lca] + dep[y] - 2 * dep[rt] - K));
  return ST::query(x, dfn[p], dfn[p] + size[p] - 1);
}
void merge(int x, int y) {
  if (P[id[x]].size() > P[id[y]].size()) {
    for (auto i : P[id[y]]) ans += calc(x, x, i);
    for (auto i : P[id[y]]) P[id[x]].insert(i);
  } else {
    std::swap(id[x], id[y]);
    for (auto i : P[id[y]]) ans += calc(x, y, i);
    for (auto i : P[id[y]]) P[id[x]].insert(i);
  }
  ST::merge(x, y);
}
void solve(int x) {
  for (int e = head[x]; e; e = nxt[e]) solve(to[e]);
  P[id[x] = x] = {vec[x].begin(), vec[x].end()};
  for (auto i : vec[x]) ans += calc(x, x, i), ST::Insert(x, dfn[i]);
  for (int e = head[x]; e; e = nxt[e]) merge(x, to[e]);
}
void solve() {
  for (int e = head[rt]; e; e = nxt[e]) solve(to[e]);
}
}  // namespace virtual_tree
std::vector<int> vec[max_N];
void solve() {
  for (int i = 1; i <= m; i++)
    if (P[i].u != P[i].lca && P[i].v != P[i].lca) vec[P[i].lca].push_back(i);
  for (int i = 1; i <= n; i++) {
    std::vector<int> tmp;
    tmp.push_back(i);
    for (auto j : vec[i]) tmp.push_back(P[j].u), tmp.push_back(P[j].v);
    virtual_tree::build(tmp);
    ST::init();
    for (auto j : vec[i]) virtual_tree::vec[P[j].u].push_back(P[j].v);
    virtual_tree::solve();
  }
}
}  // namespace work3
int main() {
  n = read(), m = read(), K = read();
  for (int i = 1, u, v; i < n; i++)
    u = read(), v = read(), T[u].push_back(v), T[v].push_back(u);
  dfs1(1), dfs2(1);
  for (int i = 1; i <= m; i++) {
    P[i].u = read(), P[i].v = read();
    if (dfn[P[i].u] > dfn[P[i].v]) std::swap(P[i].u, P[i].v);
    P[i].lca = LCA(P[i].u, P[i].v);
  }
  work1::solve(), work2::solve(), work3::solve();
  return Write(ans), 0;
}
