#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
#ifdef DEBUG
#define display(x) cerr << #x << " = " << x << endl;
#define displaya(a, st, n)\
	{cerr << #a << " = {";\
	for(int qwq = (st); qwq <= (n); ++qwq) {\
		if(qwq == (st)) cerr << a[qwq];\
		else cerr << ", " << a[qwq];\
	} cerr << "}" << endl;}
#define displayv(v) displaya(v, 0, (int)(v).size() - 1)
#endif
template<typename T> bool chmin(T &a, const T &b) { return a > b ? a = b, true : false; }
template<typename T> bool chmax(T &a, const T &b) { return a < b ? a = b, true : false; }

const int maxN = 2000 + 5;
int n, m;
struct Tree {
	int root;
	set<int> S;
	vector<int> G[maxN];
	void link(int x, int y) {
		G[x].push_back(y);
		G[y].push_back(x);
	}
	int euler[maxN], pre[maxN], post[maxN];
	int dfs_clock;
	void init(int root) {
		this->root = root;
		dfs_clock = 0;
		S.clear();
	}
	void DFS(int u, int fa) {
		for(auto p = G[u].begin(); p != G[u].end(); ++p) if(*p == fa) {
			G[u].erase(p); break;
		}
		euler[pre[u] = ++dfs_clock] = u;
		for(int &v : G[u]) {
			DFS(v, u);
		}
		post[u] = dfs_clock;
	}
	bool contains(int y) {
		return S.count(pre[y]);
	}
	int findtop(int y) {
		auto p = S.lower_bound(pre[y]);
		if(p == S.begin()) return 0;
		else {
			int u = euler[*--p];
			if(pre[u] <= pre[y] && pre[y] <= post[u]) return u;
			else return 0;
		}
	}
	void add(int y) {
		S.insert(pre[y]);
	}
	void remove(int y) {
		S.erase(pre[y]);
	}
	vector<int> headless_subtree(int y) {
		return vector<int>(euler + pre[y] + 1, euler + post[y] + 1);
	}
	void show() {
		for(int x : S) printf("%d ", euler[x]);
		printf("\n");
	}
} t[maxN];

void link(int x, int y) {
//	printf("link %d %d\n", x, y);
	if(t[x].contains(y)) return;
	else if(t[x].findtop(y)) link(t[x].findtop(y), y);
	else if(t[y].findtop(x)) link(t[y].findtop(x), x);
	else {
		t[x].add(y);
		t[y].add(x);
		vector<pii> plan;
		int T = 2;
		while(T--) {
			auto vec = t[x].headless_subtree(y);
			for(int u : vec) if(t[x].contains(u)) {
				t[x].remove(u); t[u].remove(x);
				plan.emplace_back(y, u);
			}
			swap(x, y);
		}
		for(pii p : plan) link(p.first, p.second);
	}
}

short ok[maxN][maxN];
bool check(int x, int y) {
	if(x > y) swap(x, y);
	short &res = ok[x][y];
	if(res != -1) return res;
	res = 0;
	if(t[x].contains(y)) res = 1;
	else {
		int k = t[y].findtop(x);
		if(k && check(k, x)) res = 1;
	}
	return res;
}

int main() {
	cin >> n >> m;
	for(int u = 1; u <= n; ++u) t[u].init(u);
	for(int i = 1; i < n; ++i) {
		int x, y; cin >> x >> y;
		for(int u = 1; u <= n; ++u) t[u].link(x, y);
	}
	for(int u = 1; u <= n; ++u) t[u].DFS(u, -1);
	for(int i = 1; i <= m; ++i) {
		int x, y; cin >> x >> y;
		link(x, y);
	}
//	for(int u = 1; u <= n; ++u) t[u].show();
	memset(ok, -1, sizeof(ok));
	int cnt = 0;
	for(int x = 1; x <= n; ++x) {
		for(int y = x + 1; y <= n; ++y) {
			cnt += check(x, y);
		}
	}
	cout << cnt << endl;
	return 0;
}
