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 = 2e5 + 5;
const int logn = 20;
int n, m;
int in[maxn], out[maxn];
int dep[maxn], par[maxn][logn];
long long ans = 0;
vector<int> g[maxn];
inline int lca(int u, int v) {
  if (dep[v] > dep[u]) swap(u, v);
  for (int i = logn - 1; i >= 0; --i)
    if (dep[u] - dep[v] >> i & 1) u = par[u][i];
  if (u == v) return u;
  for (int i = logn - 1; i >= 0; --i)
    if (par[u][i] != par[v][i]) u = par[u][i], v = par[v][i];
  return par[u][0];
}
inline int kthParent(int u, int k) {
  for (int i = logn - 1; i >= 0; --i)
    if (k >> i & 1) u = par[u][i];
  return u;
}
namespace Precalc {
int clk = 0;
inline void dfs(int u, int p) {
  in[u] = clk++;
  par[u][0] = p;
  if (~p) dep[u] = dep[p] + 1;
  for (int i = (0); i < (g[u].size()); ++i) {
    int v = g[u][i];
    if (v == p) continue;
    dfs(v, u);
  }
  out[u] = clk - 1;
  return;
}
inline void work() {
  dfs(0, -1);
  for (int i = (1); i < (logn); ++i)
    for (int u = (0); u < (n); ++u)
      par[u][i] = (~par[u][i - 1] ? par[par[u][i - 1]][i - 1] : -1);
  return;
}
}  // namespace Precalc
int k;
int r[maxn];
class FenwickTree {
 public:
  int dat[maxn];
  inline void init() {
    memset(dat, 0, sizeof(dat));
    return;
  }
  inline int query(int x) {
    int ret = 0;
    for (++x; x; x -= x & (-x)) ret += dat[x];
    return ret;
  }
  inline void update(int x, int v) {
    for (++x; x <= n; x += x & (-x)) dat[x] += v;
    return;
  }
  inline int query(int l, int r) { return query(r) - (l ? query(l - 1) : 0); }
} fen;
namespace DistinctLCA {
vector<int> qry[maxn];
inline void dfs(int u, int p, int *a, int *b) {
  for (int i = (0); i < (qry[u].size()); ++i) {
    int v = a[qry[u][i]], d = dep[v] - dep[u];
    if (d < k) continue;
    int r_ = kthParent(v, d - k);
    ans += fen.query(in[r_], out[r_]);
  }
  for (int i = (0); i < (qry[u].size()); ++i) {
    int v = b[qry[u][i]];
    fen.update(in[v], 1);
  }
  for (int i = (0); i < (g[u].size()); ++i) {
    int v = g[u][i];
    if (v == p) continue;
    dfs(v, u, a, b);
  }
  for (int i = (0); i < (qry[u].size()); ++i) {
    int v = a[qry[u][i]];
    fen.update(in[v], -1);
  }
  return;
}
inline void work(int *a, int *b) {
  fen.init();
  for (int i = (0); i < (n); ++i) qry[i].clear();
  for (int i = (0); i < (m); ++i) {
    qry[r[i]].push_back(i);
  }
  dfs(0, -1, a, b);
  return;
}
}  // namespace DistinctLCA
namespace FuckingCase {
vector<int> qry[maxn];
inline void dfs(int u, int p, int *a, int *b) {
  for (int i = (0); i < (qry[u].size()); ++i) {
    int v = a[qry[u][i]], d = dep[v] - dep[u];
    if (d >= k) {
      int r_ = kthParent(v, d - k);
      ans += fen.query(in[r_], out[r_]);
    }
    int w = b[qry[u][i]];
    fen.update(in[w], 1);
  }
  for (int i = (0); i < (g[u].size()); ++i) {
    int v = g[u][i];
    if (v == p) continue;
    dfs(v, u, a, b);
  }
  for (int i = (0); i < (qry[u].size()); ++i) {
    int w = b[qry[u][i]];
    fen.update(in[w], -1);
  }
  return;
}
inline void work(int *a, int *b) {
  fen.init();
  for (int i = (0); i < (n); ++i) qry[i].clear();
  for (int i = (0); i < (m); ++i) {
    qry[r[i]].push_back(i);
  }
  dfs(0, -1, a, b);
  return;
}
}  // namespace FuckingCase
int s[maxn], t[maxn];
namespace SameLCA {
int rt, top;
int stk[maxn];
vector<int> qry[maxn], buck[maxn];
vector<int> tree[maxn];
inline bool cmp(const int &i, const int &j) { return in[i] < in[j]; }
inline void compress(vector<int> tmp) {
  sort(tmp.begin(), tmp.end(), cmp);
  tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
  for (int i = (0); i < (tmp.size()); ++i) {
    int u = tmp[i];
    if (!top) {
      stk[++top] = u;
      continue;
    }
    int r = lca(u, stk[top]);
    for (; top > 1 && dep[stk[top - 1]] >= dep[r]; --top)
      tree[stk[top - 1]].push_back(stk[top]);
    if (stk[top] != r) {
      tree[r].push_back(stk[top]);
      stk[top] = r;
    }
    stk[++top] = u;
  }
  for (; top > 1; --top) tree[stk[top - 1]].push_back(stk[top]);
  return;
}
class SegmentTree {
 public:
  static const int siz = 262144;
  class Node {
   public:
    int ls, rs, sum;
    Node(int ls_ = 0, int rs_ = 0, int sum_ = 0)
        : ls(ls_), rs(rs_), sum(sum_) {}
  };
  int tot;
  Node dat[maxn * logn];
  SegmentTree() : tot(1) {}
  inline void init() {
    tot = 1;
    return;
  }
  inline int newNode() {
    dat[tot] = Node();
    return tot++;
  }
  inline void pushUp(int u) {
    dat[u].sum = 0;
    if (dat[u].ls) dat[u].sum += dat[dat[u].ls].sum;
    if (dat[u].rs) dat[u].sum += dat[dat[u].rs].sum;
    return;
  }
  inline void update(int &u, int y, int k, int l = 0, int r = siz - 1) {
    if (!u) u = newNode();
    if (l == r) {
      ++dat[u].sum;
      return;
    }
    int md = l + r >> 1;
    if (y <= md)
      update(dat[u].ls, y, k, l, md);
    else
      update(dat[u].rs, y, k, md + 1, r);
    pushUp(u);
    return;
  }
  inline void merge(int &u, int v, int l = 0, int r = siz - 1) {
    if (!u || !v) {
      u = (u ^ v);
      return;
    }
    if (l == r) return;
    int md = l + r >> 1;
    merge(dat[u].ls, dat[v].ls, l, md);
    merge(dat[u].rs, dat[v].rs, md + 1, r);
    pushUp(u);
    return;
  }
  inline int query(int &u, int s, int t, int l = 0, int r = siz - 1) {
    if (!u) return 0;
    if (l >= s && r <= t) return dat[u].sum;
    int md = l + r >> 1, ret = 0;
    if (s <= md) ret += query(dat[u].ls, s, t, l, md);
    if (t > md) ret += query(dat[u].rs, s, t, md + 1, r);
    return ret;
  }
} seg;
class Node {
 public:
  int rt;
  vector<int> vec;
  Node() : rt(0) {
    vec.clear();
    return;
  }
  inline int size() { return vec.size(); }
};
inline void merge(Node *&S, Node *&T, int r1) {
  if (S->size() < T->size()) swap(S, T);
  for (int i = (0); i < (T->size()); ++i) {
    int id = T->vec[i];
    int k1 = dep[r1] - dep[rt];
    if (k1 >= k) {
      ans += seg.query(S->rt, in[rt], out[rt]);
      continue;
    }
    int k2 = k - k1;
    if (dep[t[id]] - dep[rt] < k2) continue;
    int r2 = kthParent(t[id], dep[t[id]] - dep[rt] - k2);
    ans += seg.query(S->rt, in[r2], out[r2]);
  }
  for (int i = (0); i < (T->size()); ++i) S->vec.push_back(T->vec[i]);
  seg.merge(S->rt, T->rt);
  T->vec.clear();
  return;
}
inline Node *dfs(int u, int p) {
  Node *ret = new Node();
  for (int i = (0); i < (tree[u].size()); ++i) {
    int v = tree[u][i];
    if (v == p) continue;
    Node *res = dfs(v, u);
    merge(ret, res, u);
  }
  for (int i = (0); i < (qry[u].size()); ++i) {
    Node *res = new Node();
    int id = qry[u][i];
    res->vec.push_back(id);
    seg.update(res->rt, in[t[id]], 1);
    merge(ret, res, u);
  }
  return ret;
}
inline void clear(int u, int p) {
  for (int i = (0); i < (tree[u].size()); ++i) {
    int v = tree[u][i];
    clear(v, u);
  }
  tree[u].clear();
  return;
}
inline void work() {
  for (int i = (0); i < (m); ++i) {
    buck[r[i]].push_back(i);
  }
  for (int i = (0); i < (n); ++i) {
    vector<int> tmp;
    tmp.push_back(i);
    for (int j = (0); j < (buck[i].size()); ++j) {
      int id = buck[i][j];
      tmp.push_back(s[id]);
      qry[s[id]].push_back(id);
    }
    compress(tmp);
    rt = i;
    dfs(i, -1);
    clear(i, -1);
    seg.init();
    for (int j = (0); j < (buck[i].size()); ++j) {
      int id = buck[i][j];
      qry[s[id]].clear();
    }
    top = 0;
  }
  return;
}
}  // namespace SameLCA
int main() {
  scanf("%d%d%d", &n, &m, &k);
  for (int i = (1); i < (n); ++i) {
    int u, v;
    scanf("%d%d", &u, &v);
    --u;
    --v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  Precalc::work();
  for (int i = (0); i < (m); ++i) {
    scanf("%d%d", s + i, t + i);
    --s[i], --t[i];
    if (in[s[i]] > in[t[i]]) swap(s[i], t[i]);
    r[i] = lca(s[i], t[i]);
  }
  DistinctLCA::work(s, s);
  DistinctLCA::work(t, t);
  FuckingCase::work(s, t);
  FuckingCase::work(t, s);
  SameLCA::work();
  printf("%lld\n", ans);
  return 0;
}
