// #define DEBUGGING #include using namespace std; #define endl '\n' #define ALL(V) (V).begin(), (V).end() #define ALLR(V) (V).rbegin(), (V).rend() template using V = std::vector; template using VV = V>; using ll = std::int64_t; using ull = std::uint64_t; using PLL = std::pair; using TLL = std::tuple; template const T& var_min(const T &t) { return t; } template const T& var_max(const T &t) { return t; } template const T& var_min(const T &t, const Tail&... tail) { return std::min(t, var_min(tail...)); } template const T& var_max(const T &t, const Tail&... tail) { return std::max(t, var_max(tail...)); } template void chmin(T &t, const Tail&... tail) { t = var_min(t, tail...); } template void chmax(T &t, const Tail&... tail) { t = var_max(t, tail...); } template const T& clamp(const T &t, const T &low, const T &high) { return std::max(low, std::min(high, t)); } template void chclamp(T &t, const T &low, const T &high) { return t = clamp(t, low, high); } namespace init__ { struct InitIO { InitIO() { std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); std::cout << std::fixed << std::setprecision(30); } } init_io; } #define mv_rec make_v(init, tail...) template T make_v(T init) { return init; } template auto make_v(T init, size_t s, Tail... tail) { return V(s, mv_rec); } #undef mv_rec #ifdef DEBUGGING #include "../../debug/debug.cpp" #else #define DEBUG(...) 0 #define DEBUG_SEPARATOR_LINE 0 #endif ll N; VV edges; V cnt_from; V prop_val; PLL dfs1(ll cur, ll pre, ll prop, ll add_v) { ll add_sum = 0; add_v += cnt_from[cur]; for(ll nxt : edges[cur]) if(nxt != pre) { ll a, b; tie(a, b) = dfs1(nxt, cur, prop + add_v, add_v); prop_val[cur] += a + b; add_sum += b; } ll fst = prop_val[cur]; ll snd = add_sum + cnt_from[cur]; prop_val[cur] += prop; return PLL(fst, snd); } ll dfs2(ll cur, ll pre, ll prop, ll add_v) { prop += add_v; ll ret = prop_val[cur] + prop; for(ll nxt : edges[cur]) if(nxt != pre) chmin(ret, dfs2(nxt, cur, prop, add_v)); return ret; } ll calc_from_root(ll root) { V ret_lis(edges[root].size()); ll add_sum = 0; for(ll i = 0; i < edges[root].size(); i++) { ll a, b; tie(a, b) = dfs1(edges[root][i], root, cnt_from[root], cnt_from[root]); ret_lis[i] = PLL(a + b, b); prop_val[root] += a + b; add_sum += b; } ll ret = prop_val[root]; for(ll i = 0; i < edges[root].size(); i++) { ll prop = prop_val[root] - ret_lis[i].first; ll add_v = add_sum - ret_lis[i].second; chmin(ret, dfs2(edges[root][i], root, prop, add_v)); } return ret; } struct UnionFind { V parents, rank; UnionFind(ll N) : parents(N), rank(N, 1) { iota(ALL(parents), 0ll); } ll find(ll x) { return parents[x] == x ? x : parents[x] = find(parents[x]); } void unit(ll x, ll y) { ll px = find(x); ll py = find(y); if(px == py) return; if(rank[px] < rank[py]) swap(px, py); rank[px] += rank[px] == rank[py]; parents[py] = px; } bool is_same(ll x, ll y) { return find(x) == find(y); } }; struct LCA { V depth; VV dp; LCA(const VV &edges, const V &roots) : depth(edges.size()), dp(make_v(0, edges.size(), 20)) { for(ll root : roots) dfs(root, -1, edges); for(ll k = 1; k < 20; k++) for(ll i = 0; i < edges.size(); i++) { ll p = dp[i][k - 1]; if(p == -1) continue; dp[i][k] = dp[p][k - 1]; } } void dfs(ll cur, ll pre, const VV &edges, ll d = 0) { dp[cur][0] = pre; depth[cur] = d; for(ll nxt : edges[cur]) if(nxt != pre) dfs(nxt, cur, edges, d + 1); } ll get_par(ll x, ll dist) { ll cur = x; for(ll k = 0; k < 20 && cur != -1; k++) if((dist >> k) & 1) cur = dp[cur][k]; return cur; } ll get_lca(ll x, ll y) { if(depth[y] < depth[x]) swap(x, y); if(get_par(y, depth[y] - depth[x]) == x) return x; ll ok = 0, ng = max(depth[x], depth[y]); while(ng - ok > 1) { ll mid = (ok + ng) / 2; (get_par(x, mid) == get_par(y, mid) ? ok : ng) = mid; } return get_par(x, depth[x] - ok); } ll get_dist(ll x, ll y) { ll lca = get_lca(x, y); return (depth[x] - depth[lca]) + (depth[y] - depth[lca]); } }; int main() { ll N, M, Q; cin >> N >> M >> Q; edges.resize(N); cnt_from.resize(N); prop_val.resize(N); UnionFind uf(N); while(M--) { ll u, v; cin >> u >> v; u--; v--; edges[u].push_back(v); edges[v].push_back(u); uf.unit(u, v); } V plis(N); for(ll i = 0; i < N; i++) plis[i] = uf.find(i); sort(ALL(plis)); auto ite = unique(ALL(plis)); plis.erase(ite, plis.end()); LCA lca(edges, plis); ll ans = 0; while(Q--) { ll a, b; cin >> a >> b; a--; b--; if(uf.is_same(a, b)) { ans += lca.get_dist(a, b); } else { cnt_from[a]++; cnt_from[b]++; } } DEBUG(cnt_from); for(ll root : plis) ans += calc_from_root(root); cout << ans << endl; return 0; }