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 = 1.5e5 + 5;
const int LOG = 19;
struct Change {
  int who, prv, curr;
};
class Fenwick {
  int tot;
  vector<int> f;

 public:
  Fenwick(int n) {
    tot = 0;
    f.resize(n + 1);
  }
  Fenwick() {}
  void update(int x, int val) {
    tot += val;
    for (x++; x < f.size(); x += x & -x) f[x] += val;
  }
  int get(int x) const {
    int res = tot;
    for (x++; x; x -= x & -x) res -= f[x];
    return res;
  }
};
class UnionFind {
  vector<int> idx;
  vector<vector<int>> comp;
  stack<pair<int, Change>> ch;

 public:
  vector<int> dad;
  vector<unordered_map<int, int>> cnt;
  UnionFind(int n, vector<int> _idx) {
    idx = _idx;
    dad.resize(n);
    comp.resize(n);
    cnt.resize(n);
    for (int i = 0; i < n; i++) {
      comp[i].push_back(i);
      dad[i] = i;
    }
  }
  vector<Change> revert(int lvl) {
    vector<Change> res;
    for (; !ch.empty() && ch.top().first < lvl; ch.pop()) {
      Change tmp = ch.top().second;
      dad[tmp.who] = tmp.prv;
      tmp.who = idx[tmp.who];
      res.push_back(tmp);
    }
    return res;
  }
  void modify(int lvl, int who, int val) {
    ch.push({lvl, {who, dad[who], val}});
    dad[who] = val;
  }
  long long join(int x, int y, int lvl) {
    x = dad[x];
    y = dad[y];
    if (comp[x].size() > comp[y].size()) swap(x, y);
    long long res = 0;
    for (auto it : cnt[x]) {
      int &ref = cnt[y][it.first];
      res += (long long)it.second * ref;
      ref += it.second;
    }
    for (auto it : comp[x]) {
      comp[y].push_back(it);
      modify(lvl, it, y);
    }
    return res;
  }
  long long sweep(const vector<int> &v, UnionFind &other, int k) {
    int n = v.size() + 1;
    vector<pair<int, int>> events;
    for (int i = 0; i < n - 1; i++) events.push_back({v[i], i});
    sort(events.begin(), events.end(), greater<pair<int, int>>());
    long long res = 0;
    for (auto it : events) {
      if (k) {
        vector<Change> tmp = other.revert(k - it.first);
        for (auto it : tmp) {
          cnt[dad[it.who]][it.curr]--;
          cnt[dad[it.who]][it.prv]++;
        }
      }
      res += join(it.second, it.second + 1, it.first);
    }
    return res;
  }
};
int N, M, K;
int pos[MAXN];
int ext[MAXN];
int s[MAXN], t[MAXN], l[MAXN];
vector<int> adj[MAXN];
vector<int> toDo[MAXN];
vector<int> toExtend[MAXN];
vector<int> toAdd[MAXN], queries[MAXN];
int disc[MAXN], dep[MAXN], newDep[MAXN];
int anc[MAXN][LOG];
Fenwick byDepth;
int timer;
void load() {
  scanf("%d%d%d", &N, &M, &K);
  for (int i = 1; i < N; i++) {
    int u, v;
    scanf("%d%d", &u, &v);
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  for (int i = 0; i < M; i++) scanf("%d%d", s + i, t + i);
}
void dfs(int x, int p) {
  anc[x][0] = p;
  disc[x] = timer++;
  for (auto it : adj[x])
    if (it != p) {
      dep[it] = dep[x] + 1;
      dfs(it, x);
    }
}
int jmp(int x, int k) {
  for (int i = 0; i < LOG; i++)
    if (k >> i & 1) x = anc[x][i];
  return x;
}
int lca(int x, int y) {
  if (dep[x] < dep[y]) swap(x, y);
  x = jmp(x, dep[x] - dep[y]);
  if (x == y) return x;
  for (int i = LOG - 1; i >= 0; i--)
    if (anc[x][i] != anc[y][i]) {
      x = anc[x][i];
      y = anc[y][i];
    }
  return anc[x][0];
}
long long same_lca() {
  long long res = 0;
  for (int i = 1; i <= N; i++) {
    if (toDo[i].size() <= 1) continue;
    vector<pair<int, int>> st, en;
    for (auto it : toDo[i]) {
      st.push_back({disc[s[it]], it});
      en.push_back({disc[t[it]], it});
    }
    sort(st.begin(), st.end());
    sort(en.begin(), en.end());
    vector<int> lft, rig, perm;
    for (int j = 0; j < st.size(); j++) {
      pos[st[j].second] = j;
      if (j)
        lft.push_back(dep[lca(s[st[j - 1].second], s[st[j].second])] - dep[i]);
    }
    for (int j = 0; j < en.size(); j++) {
      perm.push_back(pos[en[j].second]);
      if (j)
        rig.push_back(dep[lca(t[en[j - 1].second], t[en[j].second])] - dep[i]);
    }
    int n = perm.size();
    UnionFind L(n, {});
    UnionFind R(n, perm);
    R.sweep(rig, L, 0);
    for (int j = 0; j < n; j++) L.cnt[perm[j]][R.dad[j]]++;
    res += L.sweep(lft, R, K);
  }
  return res;
}
long long calc(int x, int p) {
  for (auto it : toAdd[x]) byDepth.update(it, 1);
  long long res = 0;
  for (auto it : queries[x]) res += byDepth.get(it);
  for (auto it : adj[x])
    if (it != p) res += calc(it, x);
  for (auto it : toAdd[x]) byDepth.update(it, -1);
  return res;
}
void recalc(int x, int p, int d) {
  newDep[x] = d;
  for (auto it : toExtend[x]) ext[it] = ++d;
  for (auto it : adj[x])
    if (it != p) recalc(it, x, d + 1);
}
long long different_lca() {
  recalc(1, 0, 0);
  byDepth = Fenwick(N + M + 1);
  for (int i = 0; i < M; i++) {
    int modified = l[i] == s[i] ? ext[i] : newDep[l[i]];
    for (auto it : {s[i], t[i]}) {
      queries[it].push_back(modified);
      int len = dep[it] - dep[l[i]];
      if (len >= K) toAdd[jmp(it, len - K)].push_back(modified);
    }
  }
  return calc(1, 0);
}
long long solve() {
  dfs(1, 0);
  for (int j = 1; j < LOG; j++)
    for (int i = 1; i <= N; i++) anc[i][j] = anc[anc[i][j - 1]][j - 1];
  for (int i = 0; i < M; i++) {
    if (disc[s[i]] > disc[t[i]]) swap(s[i], t[i]);
    l[i] = lca(s[i], t[i]);
    if (l[i] == s[i])
      toExtend[l[i]].push_back(i);
    else
      toDo[l[i]].push_back(i);
  }
  return same_lca() + different_lca();
}
int main() {
  load();
  printf("%lld\n", solve());
  return 0;
}
