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>
const int mxn = 1 << 18;
const int lg = 18;
struct TREE {
  int n;
  std::vector<int> adj[mxn];
  int fa[mxn];
  int jump[mxn][lg];
  int sz[mxn], dep[mxn];
  int dfn[mxn], ed[mxn], on[mxn];
  void dfs0(int u, int p) {
    static int tim = 0;
    on[tim] = u;
    dfn[u] = tim++;
    sz[u] = 1;
    fa[u] = jump[u][0] = u ? p : 0;
    for (int i = 0; i < (int)(lg - 1); ++i)
      jump[u][i + 1] = jump[jump[u][i]][i];
    for (int i = 0; i < (int)(adj[u].size()); ++i) {
      int v = adj[u][i];
      if (v == p) continue;
      dep[v] = dep[u] + 1;
      dfs0(v, u);
      sz[u] += sz[v];
    }
    ed[u] = tim;
  }
  void init(int _n, std::vector<int> _adj[]) {
    n = _n;
    for (int i = 0; i < (int)(n); ++i) adj[i] = _adj[i];
    dfs0(0, -1);
  }
  int lca(int u, int v) {
    if (dep[u] > dep[v]) std::swap(u, v);
    for (int i = lg - 1; ~i; --i)
      if ((dep[v] - dep[u]) >> i & 1) v = jump[v][i];
    if (u == v) return u;
    for (int i = lg - 1; ~i; --i)
      if (jump[u][i] != jump[v][i]) u = jump[u][i], v = jump[v][i];
    return fa[u];
  }
  int la(int u, int k) {
    for (int i = lg - 1; ~i; --i)
      if (k >> i & 1) u = jump[u][i];
    return u;
  }
  bool insubt(int u, int v) { return dfn[u] <= dfn[v] && ed[v] <= ed[u]; }
} tree;
struct Counter {
  int n;
  std::pair<int, int> pnt[mxn];
  int vec[lg + 1][mxn];
  void reg_point(int x, int y) { pnt[n++] = {x, y}; }
  void init() {
    std::sort(pnt, pnt + n);
    for (int i = n; i < mxn; ++i) pnt[i] = {mxn, mxn};
    for (int i = 0; i < (int)(mxn); ++i) vec[0][i] = pnt[i].second;
    for (int i = 0; i < (int)(lg); ++i)
      for (int j = 0; j < mxn; j += 1 << (i + 1))
        std::merge(vec[i] + j, vec[i] + j + (1 << i), vec[i] + j + (1 << i),
                   vec[i] + j + (1 << (i + 1)), vec[i + 1] + j);
  }
  inline int Q(int i, int a, int b, int v) {
    return std::lower_bound(vec[i] + a, vec[i] + b, v) - (vec[i] + a);
  }
  int query(int l, int r, int v, int i, int a, int b) {
    if (l <= a && b <= r) return Q(i, a, b, v);
    if (r <= a || b <= l) return 0;
    int m = (a + b) >> 1;
    int lans = query(l, r, v, i - 1, a, m);
    int rans = query(l, r, v, i - 1, m, b);
    return lans + rans;
  }
  int query(int l, int r, int v) {
    l = std::lower_bound(pnt, pnt + n, (std::pair<int, int>){l, 0}) - pnt;
    r = std::lower_bound(pnt, pnt + n, (std::pair<int, int>){r, 0}) - pnt;
    return query(l, r, v, lg, 0, mxn);
  }
} cnter;
struct SEG {
  struct Node {
    int s;
    Node *ls, *rs;
  };
  void insert(Node *&i, int a, int b, int x) {
    if (!i) i = new Node(), i->s = 0, i->ls = i->rs = NULL;
    i->s += 1;
    if (a + 1 == b) return;
    int m = (a + b) >> 1;
    if (x < m)
      insert(i->ls, a, m, x);
    else
      insert(i->rs, m, b, x);
  }
  int query(Node *i, int a, int b, int l, int r) {
    if (!i) return 0;
    if (r <= a || b <= l) return 0;
    if (l <= a && b <= r) return i->s;
    int m = (a + b) >> 1;
    return query(i->ls, a, m, l, r) + query(i->rs, m, b, l, r);
  }
  void print(Node *i, int a, int b, std::vector<int> &v) {
    if (!i) return;
    if (a + 1 == b) {
      for (int s = 0; s < (int)(i->s); ++s) v.push_back(a);
      return;
    }
    int m = (a + b) >> 1;
    print(i->ls, a, m, v);
    print(i->rs, m, b, v);
  }
} seg;
int n, q, k;
std::vector<int> adj[mxn];
std::pair<int, int> qry[mxn];
long long ans = 0;
std::vector<std::pair<int, int> > qon[mxn];
int vec[mxn << 1], vsz;
int stk[mxn], top;
std::vector<int> nadj[mxn];
std::vector<int> info[mxn];
int nwlca;
SEG::Node *rt[mxn];
bool compdfn(int u, int v) { return tree.dfn[u] < tree.dfn[v]; }
void dfs0(int u) {
  int son = -1;
  for (int i = 0; i < (int)(nadj[u].size()); ++i) {
    int v = nadj[u][i];
    dfs0(v);
    if (son == -1 || (rt[v] ? rt[v]->s : 0) > (rt[son] ? rt[son]->s : 0))
      son = v;
  }
  rt[u] = son == -1 ? NULL : rt[son];
  for (int i = 0; i < (int)(nadj[u].size()); ++i) {
    int v = nadj[u][i];
    if (v == son) continue;
    std::vector<int> vec;
    seg.print(rt[v], 0, mxn, vec);
    if (tree.dep[u] - tree.dep[nwlca] < k) {
      for (int j = 0; j < (int)(vec.size()); ++j) {
        int x = tree.on[vec[j]];
        if (tree.dep[x] >=
            tree.dep[nwlca] + k - (tree.dep[u] - tree.dep[nwlca])) {
          int y = tree.la(x, tree.dep[x] - (tree.dep[nwlca] + k -
                                            (tree.dep[u] - tree.dep[nwlca])));
          if (u != nwlca)
            ans += seg.query(rt[u], 0, mxn, tree.dfn[y], tree.ed[y]);
        }
      }
    }
    for (int j = 0; j < (int)(vec.size()); ++j) {
      seg.insert(rt[u], 0, mxn, vec[j]);
    }
  }
  for (int i = 0; i < (int)(info[u].size()); ++i) {
    int x = info[u][i];
    if (tree.dep[u] - tree.dep[nwlca] < k) {
      if (tree.dep[x] >=
          tree.dep[nwlca] + k - (tree.dep[u] - tree.dep[nwlca])) {
        int y = tree.la(x, tree.dep[x] - (tree.dep[nwlca] + k -
                                          (tree.dep[u] - tree.dep[nwlca])));
        if (u != nwlca)
          ans += seg.query(rt[u], 0, mxn, tree.dfn[y], tree.ed[y]);
      }
    }
    seg.insert(rt[u], 0, mxn, tree.dfn[x]);
  }
}
int main() {
  scanf("%d %d %d", &n, &q, &k);
  for (int i = 0; i < (int)(n - 1); ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    --u, --v;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  for (int i = 0; i < (int)(q); ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    --u, --v;
    qry[i] = {u, v};
  }
  tree.init(n, adj);
  for (int i = 0; i < (int)(q); ++i) {
    int u = qry[i].first;
    int v = qry[i].second;
    int l = tree.lca(u, v);
    cnter.reg_point(tree.dfn[u], tree.dep[l]);
    cnter.reg_point(tree.dfn[v], tree.dep[l]);
    qon[l].push_back({u, v});
  }
  cnter.init();
  for (int x = 0; x < (int)(n); ++x) {
    int a0 = cnter.query(tree.dfn[x], tree.ed[x], tree.dep[x] - k);
    int a1 = cnter.query(tree.dfn[x], tree.ed[x], tree.dep[x] - k + 1);
    ans += long long(a0) * (a1 - a0);
  }
  for (int l = 0; l < (int)(n); ++l) {
    std::vector<std::pair<std::pair<int, int>, int> > nqon;
    for (int i = 0; i < (int)(qon[l].size()); ++i) {
      int u = qon[l][i].first;
      int v = qon[l][i].second;
      int flag = 0;
      if (tree.dep[u] - tree.dep[l] >= k) {
        flag |= 1;
        u = tree.la(u, tree.dep[u] - (tree.dep[l] + k));
      }
      if (tree.dep[v] - tree.dep[l] >= k) {
        flag |= 2;
        v = tree.la(v, tree.dep[v] - (tree.dep[l] + k));
      }
      if (!flag) continue;
      nqon.push_back({{u, v}, flag});
    }
    if (nqon.size() <= 1) continue;
    std::map<int, std::vector<int> > qwq;
    for (int i = 0; i < (int)(nqon.size()); ++i) {
      int u = nqon[i].first.first;
      int v = nqon[i].first.second;
      int flag = nqon[i].second;
      if (flag & 1)
        qwq[u].push_back(v == l ? l
                                : tree.la(v, tree.dep[v] - tree.dep[l] - 1));
      if (flag & 2)
        qwq[v].push_back(u == l ? l
                                : tree.la(u, tree.dep[u] - tree.dep[l] - 1));
    }
    for (auto x : qwq) {
      int u = x.first;
      std::vector<int> vec = x.second;
      std::sort(vec.begin(), vec.end());
      ans += long long(vec.size()) * (vec.size() - 1) / 2;
      int las = 0;
      for (int i = 0; i < (int)(vec.size()); ++i) {
        if (i && vec[i] != vec[i - 1]) {
          if (vec[las] != l) ans -= long long(i - las) * (i - las - 1) / 2;
          las = i;
        }
      }
      if (vec[las] != l)
        ans -= long long(vec.size() - las) * (vec.size() - las - 1) / 2;
    }
  }
  k = std::max(k, 2);
  for (int l = 0; l < (int)(n); ++l) {
    if (qon[l].size() <= 1) continue;
    vsz = 0;
    for (int i = 0; i < (int)(qon[l].size()); ++i) {
      int u = qon[l][i].first;
      int v = qon[l][i].second;
      vec[vsz++] = u;
      vec[vsz++] = v;
    }
    std::sort(vec, vec + vsz, compdfn);
    vsz = std::unique(vec, vec + vsz) - vec;
    int osz = vsz;
    for (int i = 0; i < (int)(osz - 1); ++i)
      vec[vsz++] = tree.lca(vec[i], vec[i + 1]);
    std::sort(vec, vec + vsz, compdfn);
    vsz = std::unique(vec, vec + vsz) - vec;
    for (int i = 0; i < (int)(vsz); ++i) nadj[vec[i]].clear();
    top = 0;
    for (int i = 0; i < (int)(vsz); ++i) {
      int u = vec[i];
      while (top >= 1 && !tree.insubt(stk[top - 1], u)) --top;
      if (top) nadj[stk[top - 1]].push_back(u);
      stk[top++] = u;
    }
    for (int i = 0; i < (int)(vsz); ++i) info[vec[i]].clear();
    for (int i = 0; i < (int)(qon[l].size()); ++i) {
      int u = qon[l][i].first;
      int v = qon[l][i].second;
      if (u == l || v == l) continue;
      if (tree.dfn[u] > tree.dfn[v]) std::swap(u, v);
      info[u].push_back(v);
    }
    nwlca = l;
    dfs0(vec[0]);
  }
  printf("%lld\n", ans);
  return 0;
}
