#include
using namespace std;
typedef long long dint; #ifdef WIN32 #define lld “%I64d” #else #define lld “%lld” #endif #define _l (long long int)
struct seg { int s; seg *ch[2]; }; struct edge { int t; edge *next; }; struct path { int u, v; inline void read() { scanf("%d%d", &u, &v); } };
const int maxn = 100009; const int maxl = 19;
seg sbuf_arr[maxn * maxl], *sbuf(sbuf_arr), *rt[maxn]; dint su, sd; int n, m, ut[maxn][maxl]; int d[maxn], dfo[maxn], dfb[maxn], dfe[maxn]; edge ebuf_arr[maxn « 1], *ebuf(ebuf_arr), *head[maxn]; path q[maxn];
inline void addEdge(int u, int v) { ebuf-> t = v; ebuf-> next = head[u]; head[u] = ebuf ++; }
inline bool cmpPath(const path& a, const path& b) { return dfb[a. u] < dfb[b. u]; }
void buildTree() { static int stc[maxn]; int tst(1), dfn(0); memset(d, 0, sizeof(d)); d[stc[1] = 1] = 1; while (tst) { int p(stc[tst –]); dfo[dfb[p] = ++ dfn] = p; dfe[p] = dfb[p]; for (int i = 1; i < maxl; ++ i) ut[p][i] = ut[ut[p][i - 1]][i - 1]; for (edge* e = head[p]; e; e = e-> next) if (!d[e-> t]) { d[e-> t] = d[p] + 1; ut[e-> t][0] = p; stc[++ tst] = e-> t; } } for (int i = n; i > 1; – i) { int p(dfo[i]), q(ut[p][0]); if (dfe[p] > dfe[q]) dfe[q] = dfe[p]; } }
#define chof(q,t) ((q)?(q->ch[t]):0) #define sof(q) ((q)?(q->s):0)
seg psgtIns(seg q, int po) { seg *s(sbuf ++), p(s); int l(1), r(n + 1); while (l + 1 < r) { p-> s = sof(q) + 1; int md((l + r) » 1), d(po >= md); p-> ch[d ^ 1] = chof(q, d ^ 1); q = chof(q, d); p-> ch[d] = sbuf ++; p = p-> ch[d]; if (d) l = md; else r = md; } p-> s = sof(q) + 1; return s; } int psgtQry(seg p, int po) { if (po < 1) return 0; int s(0), l(1), r(n + 1); while (l + 1 < r && p) { int md((l + r) » 1); if (po < md) { r = md; p = p-> ch[0]; } else { l = md; s += sof(p-> ch[0]); p = p-> ch[1]; } } return s + sof(p); }
int cntPath(int la, int ra, int lb, int rb) { if (la > ra || lb > rb) return 0; else return psgtQry(rt[ra], rb) - psgtQry(rt[ra], lb - 1) - psgtQry(rt[la - 1], rb) + psgtQry(rt[la - 1], lb - 1); }
dint gcd(dint a, dint b) { while (a) { dint c(b % a); b = a; a = c; } return b; }
int main() { #ifndef ONLINE_JUDGE freopen(".in", “r”, stdin); #endif
scanf("%d%d", &n, &m);
sd = _l m * (m - 1) / 2;
memset(head, 0, sizeof(head));
for (int i = 1; i < n; ++ i) {
int u, v;
scanf("%d%d", &u, &v);
addEdge(u, v);
addEdge(v, u);
}
buildTree();
for (int i = 0; i < m; ++ i) {
q[i]. read();
if (dfb[q[i]. u] > dfb[q[i]. v])
swap(q[i]. u, q[i]. v);
}
sort(q, q + m, cmpPath);
rt[0] = 0;
for (int i = 1, j = 0; i <= n; ++ i) {
rt[i] = rt[i - 1];
for (; j < m && q[j]. u == dfo[i]; ++ j)
rt[i] = psgtIns(rt[i], dfb[q[j]. v]);
}
su = 0;
for (int i = 0; i < m; ++ i) {
int u(q[i]. u), v(q[i]. v);
if (d[u] > d[v])
swap(u, v);
if (dfb[v] >= dfb[u] && dfb[v] <= dfe[u]) {
int p(v);
for (int i = maxl - 1; i >= 0; -- i)
if (d[ut[p][i]] > d[u])
p = ut[p][i];
su += cntPath(1, dfb[p] - 1, dfb[v], dfe[v]);
su += cntPath(dfb[v], dfe[v], dfe[p] + 1, n);
}
else {
if (dfb[u] > dfb[v])
swap(u, v);
su += cntPath(dfb[u], dfe[u], dfb[v], dfe[v]);
}
}
su -= m;
int g(gcd(su, sd));
su /= g, sd /= g;
printf(lld "/" lld "\n", su, sd);
}