#define _USE_MATH_DEFINES #include using namespace std; class UnionFind { private: int siz; vector a; public: UnionFind(int x) : siz(x), a(x, -1) {} int root(int x) { return a[x] < 0 ? x : a[x] = root(a[x]); } bool unite(int x, int y) { x = root(x); y = root(y); if (x == y) return false; siz--; if (a[x] > a[y]) swap(x, y); a[x] += a[y]; a[y] =x; return true; } bool same(int x, int y) { return root(x) == root(y); } int size(int x) { return -a[root(x)]; } int connected_component() { return siz; } }; class LowestCommonAncestor { private: static const int MAX_SIZE = 30; vector> graph; vector parent[MAX_SIZE]; vector depth; int bit_length; void copy(const vector g[], int siz) { graph.resize(siz); for (int i = 0; i < siz; ++i) for (int j : g[i]) graph[i].push_back(j); } void copy(const vector>& g, int siz = -1) { if (siz < 0) siz = (int) g.size(); graph.resize(siz); for (int i = 0; i < siz; ++i) for (int j : g[i]) graph[i].push_back(j); } void initialize() { int siz = (int) graph.size(); int root = 0; bit_length = 1; while ((1 << bit_length) < siz) ++bit_length; for (int i = 0; i < bit_length; ++i) parent[i].resize(siz); depth.assign(siz, -1); dfs(root, -1, 0); for (int i = 0; i < bit_length- 1; ++i) { for (int v = 0; v < siz; ++v) { if (depth[v] == -1) continue; if (parent[i][v] < 0) parent[i + 1][v] = -1; else parent[i + 1][v] = parent[i][parent[i][v]]; } } } void dfs(int cur, int par, int d) { parent[0][cur] = par; depth[cur] = d; for (int child : graph[cur]) if (child != par) dfs(child, cur, d + 1); } public: LowestCommonAncestor() {} LowestCommonAncestor(const vector>& g, int siz = -1) { build(g, siz); } LowestCommonAncestor(const vector g[], int siz) { build(g, siz); } void build(const vector g[], int siz) { copy(g, siz); initialize(); } void build(const vector>& g, int siz = -1) { copy(g, siz); initialize(); } int get(int u, int v) { if (depth[u] > depth[v]) swap(u, v); for (int i = 0; i < bit_length; ++i) if (((depth[v] - depth[u]) >> i) & 1) v = parent[i][v]; if (u == v) return u; for (int i = bit_length - 1; i >= 0; --i) if (parent[i][u] != parent[i][v]) u = parent[i][u], v = parent[i][v]; return parent[0][u]; } }; using LCA = LowestCommonAncestor; void dfs_depth (int cur, int par, vector& depth, const vector>& g) { for (int child : g[cur]) if (child != par) { depth[child] = depth[cur] + 1; dfs_depth(child, cur, depth, g); } } void dfs1 (int cur, int par, vector& num, vector& dp, const vector& counts, const vector>& g) { num[cur] += counts[cur]; for (int child : g[cur]) if (child != par) { dfs1(child, cur, num, dp, counts, g); num[cur] += num[child]; dp[cur] += dp[child] + num[child]; } } void dfs2 (int cur, int par, const vector& num, const vector& dp, const vector& counts, const vector>& g, long long x, long long y, long long& res) { res = min(res, dp[cur] + y); //cerr << cur << " " << dp[cur] << " " << x << endl; for (int child : g[cur]) if (child != par) { long long xx = num[cur] - num[child] + x; long long yy = dp[cur] - (dp[child] + num[child]) + y + xx; dfs2 (child, cur, num, dp, counts, g, xx, yy, res); } } long long calc (const vector& counts, const vector>& g) { long long res = 1LL << 60; int siz = (int) counts.size(); vector num(siz); vector dp(siz); dfs1(0, -1, num, dp, counts, g); dfs2(0, -1, num, dp, counts, g, 0, 0, res); // cerr << "num = "; // for (int i : num) cerr << i << " "; // cerr << endl; // cerr << "dp = "; // for (long long i : dp) cerr << i << " "; // cerr << endl; return res; } signed main() { ios::sync_with_stdio(false); cin.tie(0); int n, m, q; cin >> n >> m >> q; vector> 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.unite(u, v); } vector in(n, -1), pos(n); vector> group; for (int i = 0; i < n; i++) { int r = uf.root(i); if (in[r] == -1) { in[r] = (int) group.size(); group.push_back({}); } in[i] = in[r]; pos[i] = group[in[i]].size(); group[in[i]].push_back(i); } int comp_siz = (int) group.size(); vector sizes(comp_siz); vector> comp_count(comp_siz); vector>> comp_g(comp_siz); for (int i = 0; i < comp_siz; i++) { sizes[i] = (int) group[i].size(); comp_count[i].resize(sizes[i]); comp_g[i].resize(sizes[i]); } for (int i = 0; i < n; i++) { for (int nbr : g[i]) { comp_g[in[i]][pos[i]].push_back(pos[nbr]); } } vector>> query(comp_siz); for (int i = 0; i < q; i++) { int a, b; cin >> a >> b; --a; --b; if (uf.same(a, b)) { query[in[a]].emplace_back(pos[a], pos[b]); } else { ++comp_count[in[a]][pos[a]]; ++comp_count[in[b]][pos[b]]; } } long long ans = 0; //cerr << comp_siz << endl; for (int i = 0; i < comp_siz; i++) { //long long dist_in = 0, dist_out = 0; LCA lca(comp_g[i]); vector depth(sizes[i]); dfs_depth(0, -1, depth, comp_g[i]); ans += calc(comp_count[i], comp_g[i]); //dist_out += calc(comp_count[i], comp_g[i]); for (auto p : query[i]) { ans += depth[p.first] + depth[p.second] - depth[lca.get(p.first, p.second)] * 2; //dist_in += depth[p.first] + depth[p.second] - depth[lca.get(p.first, p.second)] * 2; } //cerr << i << " " << dist_in << " " << dist_out << endl; } cout << ans << '\n'; return 0; }