#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <ctime>
#include <cassert>
#include <complex>
#include <string>
#include <cstring>
#include <chrono>
#include <random>
#include <queue>
#include <bitset>
using namespace std;

#ifdef LOCAL
	#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
	#define eprintf(...) 42
#endif

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, int> pli;
typedef pair<ll, ll> pll;
typedef long double ld;
#define mp make_pair
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

typedef unsigned long long ull;
const int L = 6;
const int B = 1 << L;
const int U = B - 1;

const int N = 2002;
const int S = N / B + 1;

struct Bitset {
	ull a[S];

	Bitset() : a() {}

	void set(int p) {
		a[p >> L] |= (ull)1 << (p & U);
	}
	int get(int p) {
		return (a[p >> L] >> (p & U)) & 1;
	}
	void flip(int p) {
		a[p >> L] ^= (ull)1 << (p & U);
	}

	Bitset operator & (const Bitset &A) const {
		Bitset R = Bitset();
		for (int i = 0; i < S; i++)
			R.a[i] = a[i] & A.a[i];
		return R;
	}
	Bitset operator ^ (const Bitset &A) const {
		Bitset R = Bitset();
		for (int i = 0; i < S; i++)
			R.a[i] = a[i] ^ A.a[i];
		return R;
	}
	Bitset operator | (const Bitset &A) const {
		Bitset R = Bitset();
		for (int i = 0; i < S; i++)
			R.a[i] = a[i] | A.a[i];
		return R;
	}

	void eprint() {
		for (int i = 0; i < 10; i++)
			eprintf("%d", get(i));
		eprintf("\n");
	}
};

const int M = N * N / 2;
int n, m;
Bitset g[N];
int q[M][2];
int topQ;
Bitset toRoot[N];
Bitset subtree[N];
vector<int> G[N];
Bitset ALL;
int LCA[N][N];
vector<int> curSubtree[N];
int h[N];
int goUp[N][N];

void addQ(int v, int u) {
	g[v].set(u);
	g[u].set(v);
	q[topQ][0] = v;
	q[topQ][1] = u;
	topQ++;
}

void dfs(int v) {
	goUp[v][h[v]] = v;
	toRoot[v].set(v);
	subtree[v].set(v);
	curSubtree[v].push_back(v);
	for (int u : G[v]) {
		if (toRoot[v].get(u)) continue;
		toRoot[u] = toRoot[v];
		h[u] = h[v] + 1;
		for (int i = 0; i < h[u]; i++)
			goUp[u][i] = goUp[v][i];
		dfs(u);
		subtree[v] = subtree[v] | subtree[u];
		for (int x : curSubtree[v])
			for (int y : curSubtree[u])
				LCA[y][x] = LCA[x][y] = v;
		for (int y : curSubtree[u])
			curSubtree[v].push_back(y);
	}
}

Bitset getPath(int v, int u) {
	if (toRoot[u].get(v)) swap(v, u);
	if (toRoot[v].get(u)) {
		return (ALL ^ subtree[goUp[v][h[u] + 1]]) | toRoot[v] | subtree[v];
	} else {
		Bitset res = ((subtree[v] | subtree[u] | toRoot[v] | toRoot[u]) ^ (toRoot[v] & toRoot[u]));
		res.set(LCA[v][u]);
		return res;
	}
}

void tryAdd(int v, int u) {
//	eprintf("tryAdd %d %d\n", v, u);
	Bitset cur = getPath(v, u) & (g[v] ^ g[u]);
	for (int i = 0; i < S; i++) {
		if (cur.a[i] == 0) continue;
		for (int j = 0; j < B; j++) {
			if ((cur.a[i] >> j) & (ull)1) {
				int w = i * B + j;
				if (g[v].get(w)) {
					addQ(u, w);
				} else {
					addQ(v, w);
				}
			}
		}
	}
}

int main()
{
//	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

	scanf("%d%d", &n, &m);
	for (int i = 1; i < n; i++) {
		int v, u;
		scanf("%d%d", &v, &u);
		v--;u--;
		G[v].push_back(u);
		G[u].push_back(v);
	}
	h[0] = 0;
	dfs(0);
	for (int i = 0; i < n; i++)
		ALL.set(i);
/*
	for (int i = 0; i < n; i++)
		for (int j = 0; j < i; j++) {
			eprintf("%d %d ", i, j);
			getPath(i, j).eprint();
		}
*/
	for (int i = 0; i < n; i++)
		g[i].set(i);
	while(m--) {
		int v, u;
		scanf("%d%d", &v, &u);
		v--;u--;
		addQ(v, u);
	}
	for (int i = 0; i < topQ; i++) {
		int v = q[i][0], u = q[i][1];
		tryAdd(v, u);
	}
	printf("%d\n", topQ);

	return 0;
}


Measured memory_bytes: 59264