// base off ecnerwala's solution
#ifndef LOCAL
#define NDEBUG
#endif
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

namespace __gnu_pbds {
template <typename K, typename V=null_type>
using order_statistic_tree = tree<K, V, less<K>, rb_tree_tag, tree_order_statistics_node_update>;
}
using __gnu_pbds::order_statistic_tree;

using i64 = int64_t;

const int MAXN = 1.6e5;
int N, M, K;
vector<int> adj[MAXN];

vector<int> preorder;
int sz[MAXN];
int depth[MAXN];
int par[MAXN];

int heavyRoot[MAXN];
int st[MAXN];
int en[MAXN];

void dfs_sz(int cur, int prv) {
	if (prv != -1) {
		adj[cur].erase(find(adj[cur].begin(), adj[cur].end(), prv));
	}
	par[cur] = prv;
	depth[cur] = (prv == -1 ? 0 : depth[prv]+1);
	sz[cur] = 1;

	for (int nxt : adj[cur]) {
		dfs_sz(nxt, cur);
		sz[cur] += sz[nxt];
	}

	nth_element(adj[cur].begin(), adj[cur].begin(), adj[cur].end(), [&](int i, int j) { return sz[i] > sz[j]; });
}

void dfs_hld(int cur) {
	st[cur] = int(preorder.size());
	preorder.push_back(cur);

	heavyRoot[cur] = (par[cur] != -1 && st[cur] == st[par[cur]]+1) ? heavyRoot[par[cur]] : cur;

	for (int nxt : adj[cur]) {
		dfs_hld(nxt);
	}

	en[cur] = int(preorder.size());
}

int lca(int a, int b) {
	while (heavyRoot[a] != heavyRoot[b]) {
		// will st[a] > st[b] work? 
		if (st[a] > st[b]) {
			swap(a, b);
		}
		b = par[heavyRoot[b]];
	}
	return st[a] < st[b] ? a : b;
}

int get_anc(int cur, int k) {
	assert(k >= 0);
	int d = depth[cur] - k;
	while (d < depth[heavyRoot[cur]]) {
		cur = par[heavyRoot[cur]];
	}
	return preorder[st[cur] - (depth[cur] - d)];
}

using evt_t = pair<pair<int, int>, int>;

vector<evt_t> evts[MAXN];
i64 ans = 0;

using tree_t = order_statistic_tree<evt_t>;

tree_t dfs(int cur) {
	tree_t res;

	int curPar = depth[cur] >= K ? get_anc(cur, K-1) : -1;

	auto joinEvt = [&](pair<int, int> it) -> bool {
		auto getSubtree = [&](int n) -> int {
			return int(res.order_of_key({{en[n], -1}, -1})) - int(res.order_of_key({{st[n], -1}, -1}));
		};
		int stDest = it.first, c = it.second;
		assert(!(st[cur] <= stDest && stDest < en[cur]));
		int dest = preorder[stDest];

		int totDist = depth[cur] + depth[dest] - 2 * depth[c];
		if (totDist >= K) {
			if (depth[cur] - depth[c] >= K) {
				assert(curPar != -1);
				ans += int(res.size()) - getSubtree(curPar);
			} else {
				ans += getSubtree(get_anc(dest, totDist - K));
			}
			if (stDest >= en[cur]) {
				// event of the second kind
				assert(par[dest] == c);
				ans -= getSubtree(dest);
			}
			return true;
		} else {
			return false;
		}
	};

	for (auto it : evts[cur]) {
		if (joinEvt(it.first)) {
			res.insert(it);
		}
	}
	for (int nxt : adj[cur]) {
		auto o = dfs(nxt);
		for (auto lo = o.lower_bound({{st[cur], -1}, -1}); lo != o.end() && lo->first.first < en[cur]; ) {
			lo = o.erase(lo);
		}
		if (o.size() > res.size()) res.swap(o);
		for (auto it = o.begin(); it != o.end(); ) {
			if (joinEvt(it->first)) {
				++it;
			} else {
				it = o.erase(it);
			}
		}
		for (auto evt : o) {
			res.insert(evt);
		}
	}

	return res;
}

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> N >> M >> K;
	for (int e = 0; e < N-1; e++) {
		int u, v; cin >> u >> v; u--, v--;
		adj[u].push_back(v);
		adj[v].push_back(u);
	}

	dfs_sz(0, -1);
	preorder.reserve(N);
	dfs_hld(0);
	assert(int(preorder.size()) == N);

	int evtIdx = 0;
	for (int i = 0; i < M; i++) {
		int s, t; cin >> s >> t; s--, t--;
		if (st[s] > st[t]) swap(s, t);
		int c = lca(s, t);
		evts[t].push_back({{st[s], c}, evtIdx++});
		if (s != c) {
			assert(depth[c] < depth[t]);
			evts[s].push_back({{st[get_anc(t, depth[t] - depth[c] - 1)], c}, evtIdx++});
		}
	}

	dfs(0);
	cout << ans << '\n';

	return 0;
}
