//#define _GLIBCXX_DEBUG #include "bits/stdc++.h" using namespace std; //------------------------------- Libraries --------------------------------// class UnionFind { vector par; public: UnionFind(int n) : par(n, -1) {} int root(int x) { if (par[x] < 0) return x; else return par[x] = root(par[x]); } inline bool same(int u, int v) { return root(u) == root(v); } bool merge(int x, int y) { x = root(x); y = root(y); if (x == y) return false; if (par[x] > par[y]) swap(x, y); par[x] += par[y]; par[y] = x; return true; } int size(int x) { return -par[root(x)]; } }; class LowestCommonAncestor { //2^k >= n int n, k; vector> g, par; vector dis; inline void build() { this->calc(); this->setpar(); } void calc(int v = 0, int p = -1) { this->par[0][v] = p; for (int nv : this->g[v]) { if (nv != p) { this->dis[nv] = this->dis[v] + 1; this->calc(nv, v); } } } void setpar() { for (int i = 0; i < this->k; i++) { for (int v = 0; v < this->n; v++) { if (this->par[i][v] != -1) { this->par[i + 1][v] = this->par[i][par[i][v]]; } } } } public: LowestCommonAncestor(int n_, vector> &g_) : n(n_), g(g_) { k = log2(n + 1); this->par.resize(k + 1, vector(n, -1)); dis.resize(n); this->build(); } int get(int u, int v) { //dis[u] <= dis[v] if (this->dis[u] > this->dis[v]) { swap(u, v); } int d = this->dis[v] - this->dis[u]; for (int i = k; i >= 0; i--) { if (d >> i & 1) { v = this->par[i][v]; } } if (u == v) { return v; } for (int i = k; i >= 0; i--) { if (this->par[i][u] != this->par[i][v]) { u = this->par[i][u]; v = this->par[i][v]; } } return this->par[0][v]; } int dist(int u, int v) { return this->dis[u] + this->dis[v] - 2 * dis[this->get(u, v)]; } }; //verified @ https://onlinejudge.u-aizu.ac.jp/status/users/sifi_border/submissions/1/GRL_5_C/judge/3883181/C++14 //verified @ https://atcoder.jp/contests/abc014/submissions/7617701 //------------------------------- Type Names -------------------------------// using i64 = int_fast64_t; using seika = string; //akari : 1D, yukari : 2D, maki : 3D vector template using akari = vector; template using yukari = akari>; template using maki = akari>; //akane : ascending order, aoi : decending order template using akane = priority_queue, greater>; template using aoi = priority_queue; //------------------------------- Dubug Functions ---------------------------// inline void print() { cout << endl; } template void print(const First &first, const Rest &... rest) { cout << first << ' '; print(rest...); } //------------------------------- Solver ------------------------------------// void solve() { int n, m, q; cin >> n >> m >> q; yukari g(n); UnionFind uf(n); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; u--, v--; g[u].push_back(v); g[v].push_back(u); uf.merge(u, v); } LowestCommonAncestor lca(n, g); akari ws(n); i64 ans = 0; for (int i = 0; i < q; i++) { int a, b; cin >> a >> b; a--, b--; if (uf.same(a, b)) { ans += lca.dist(a, b); } else { ws[a]++; ws[b]++; } } akari>> dp(n); auto calc = [&](auto &&calc, int v, int p, bool flag) -> pair { if (dp[v].count(p)) { return dp[v][p]; } //res = {val, dif} pair res = make_pair(0, ws[v]); if (flag || p == -1) { for (auto nv : g[v]) { if (nv == p) { continue; } auto chi = calc(calc, nv, v, flag); res.first += chi.first + chi.second; res.second += chi.second; } } else { auto par = calc(calc, p, v, 0); auto ard = calc(calc, v, -1, 0); res.first = ard.first - par.first - par.second; res.second = ard.second - par.second; } return dp[v][p] = res; }; //uf の代表に対して呼ぶ for (int v = 0; v < n; v++) { if (v == uf.root(v)) { calc(calc, v, -1, 1); } } akari sum(n, 1e15); for (int v = 0; v < n; v++) { sum[uf.root(v)] = min(sum[uf.root(v)], calc(calc, v, -1, 0).first); //print(v, calc(calc, v, -1, 0).first, calc(calc, v, -1, 0).second); } for (int v = 0; v < n; v++) { if (v == uf.root(v)) { ans += sum[v]; } } cout << ans << endl; } int main() { solve(); return 0; }