#include using namespace std; using int64 = long long; const int mod = 1e9 + 7; const int64 infll = (1LL << 62) - 1; const int inf = (1 << 30) - 1; struct IoSetup { IoSetup() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(10); cerr << fixed << setprecision(10); } } iosetup; template< typename T1, typename T2 > ostream &operator<<(ostream &os, const pair< T1, T2 > &p) { os << p.first << " " << p.second; return os; } template< typename T1, typename T2 > istream &operator>>(istream &is, pair< T1, T2 > &p) { is >> p.first >> p.second; return is; } template< typename T > ostream &operator<<(ostream &os, const vector< T > &v) { for(int i = 0; i < (int) v.size(); i++) { os << v[i] << (i + 1 != v.size() ? " " : ""); } return os; } template< typename T > istream &operator>>(istream &is, vector< T > &v) { for(T &in : v) is >> in; return is; } template< typename T1, typename T2 > inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); } template< typename T1, typename T2 > inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); } template< typename T = int64 > vector< T > make_v(size_t a) { return vector< T >(a); } template< typename T, typename... Ts > auto make_v(size_t a, Ts... ts) { return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...)); } template< typename T, typename V > typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) { t = v; } template< typename T, typename V > typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) { for(auto &e : t) fill_v(e, v); } template< typename F > struct FixPoint : F { FixPoint(F &&f) : F(forward< F >(f)) {} template< typename... Args > decltype(auto) operator()(Args &&... args) const { return F::operator()(*this, forward< Args >(args)...); } }; template< typename F > inline decltype(auto) MFP(F &&f) { return FixPoint< F >{forward< F >(f)}; } template< typename T > struct edge { int src, to; T cost; edge(int to, T cost) : src(-1), to(to), cost(cost) {} edge(int src, int to, T cost) : src(src), to(to), cost(cost) {} edge &operator=(const int &x) { to = x; return *this; } operator int() const { return to; } }; template< typename T > using Edges = vector< edge< T > >; template< typename T > using WeightedGraph = vector< Edges< T > >; using UnWeightedGraph = vector< vector< int > >; template< typename T > using Matrix = vector< vector< T > >; struct UnionFind { vector< int > data; UnionFind(int sz) { data.assign(sz, -1); } bool unite(int x, int y) { x = find(x), y = find(y); if(x == y) return (false); if(data[x] > data[y]) swap(x, y); data[x] += data[y]; data[y] = x; return (true); } int find(int k) { if(data[k] < 0) return (k); return (data[k] = find(data[k])); } int size(int k) { return (-data[find(k)]); } }; template< typename G > struct DoublingLowestCommonAncestor { const int LOG; vector< int > dep; const G &g; vector< vector< int > > table; DoublingLowestCommonAncestor(const G &g) : g(g), dep(g.size()), LOG(32 - __builtin_clz(g.size())) { table.assign(LOG, vector< int >(g.size(), -1)); } void dfs(int idx, int par, int d) { table[0][idx] = par; dep[idx] = d; for(auto &to : g[idx]) { if(to != par) dfs(to, idx, d + 1); } } void build() { for(int i = 0; i < g.size(); i++) { if(table[0][i] == -1) { dfs(i, -1, 0); } } for(int k = 0; k + 1 < LOG; k++) { for(int i = 0; i < table[k].size(); i++) { if(table[k][i] == -1) table[k + 1][i] = -1; else table[k + 1][i] = table[k][table[k][i]]; } } } int query(int u, int v) { if(dep[u] > dep[v]) swap(u, v); for(int i = LOG - 1; i >= 0; i--) { if(((dep[v] - dep[u]) >> i) & 1) v = table[i][v]; } if(u == v) return u; for(int i = LOG - 1; i >= 0; i--) { if(table[i][u] != table[i][v]) { u = table[i][u]; v = table[i][v]; } } return table[0][u]; } }; template< typename Data, typename T > struct ReRooting { struct Node { int to, rev; Data data; }; using F1 = function< T(T, T) >; using F2 = function< T(T, Data) >; vector< vector< Node > > g; vector< vector< T > > ldp, rdp; vector< int > lptr, rptr; const F1 f1; const F2 f2; const T ident; ReRooting(int n, const F1 &f1, const F2 &f2, const T &ident) : g(n), ldp(n), rdp(n), lptr(n), rptr(n), f1(f1), f2(f2), ident(ident) {} void add_edge(int u, int v, const Data &d) { g[u].emplace_back((Node) {v, (int) g[v].size(), d}); g[v].emplace_back((Node) {u, (int) g[u].size() - 1, d}); } void add_edge_bi(int u, int v, const Data &d, const Data &e) { g[u].emplace_back((Node) {v, (int) g[v].size(), d}); g[v].emplace_back((Node) {u, (int) g[u].size() - 1, e}); } T dfs(int idx, int par) { while(lptr[idx] != par && lptr[idx] < g[idx].size()) { auto &e = g[idx][lptr[idx]]; ldp[idx][lptr[idx] + 1] = f1(ldp[idx][lptr[idx]], f2(dfs(e.to, e.rev), e.data)); ++lptr[idx]; } while(rptr[idx] != par && rptr[idx] >= 0) { auto &e = g[idx][rptr[idx]]; rdp[idx][rptr[idx]] = f1(rdp[idx][rptr[idx] + 1], f2(dfs(e.to, e.rev), e.data)); --rptr[idx]; } if(par < 0) return rdp[idx][0]; return f1(ldp[idx][par], rdp[idx][par + 1]); } vector< T > solve() { for(int i = 0; i < g.size(); i++) { ldp[i].assign(g[i].size() + 1, ident); rdp[i].assign(g[i].size() + 1, ident); lptr[i] = 0; rptr[i] = (int) g[i].size() - 1; } vector< T > ret; for(int i = 0; i < g.size(); i++) { ret.push_back(dfs(i, -1)); } return ret; } }; int main() { int N, M, Q; cin >> N >> M >> Q; UnWeightedGraph g(N); UnionFind uf(N); using pi = pair< int64, int64 >; auto f1 = [](pi a, pi b) { return pi(a.first + b.first, a.second + b.second); }; auto f2 = [](pi a, int b) { a.second += b; return pi(a.first + a.second, a.second); }; ReRooting< int, pi > ushi(N, f1, f2, pi()); vector< pair< int, int > > s; for(int i = 0; i < M; i++) { int a, b; cin >> a >> b; --a, --b; g[a].emplace_back(b); g[b].emplace_back(a); s.emplace_back(a, b); uf.unite(a, b); } DoublingLowestCommonAncestor< UnWeightedGraph > lca(g); lca.build(); vector< int > tap(N); int64 ret = 0; for(int i = 0; i < Q; i++) { int a, b; cin >> a >> b; --a, --b; if(uf.find(a) != uf.find(b)) { tap[a]++; tap[b]++; } else { int uku = lca.query(a, b); ret += lca.dep[a] + lca.dep[b] - 2 * lca.dep[uku]; } } for(auto &p : s) { ushi.add_edge_bi(p.first, p.second, tap[p.second], tap[p.first]); } auto solve = ushi.solve(); vector< int64 > latte(N, infll); for(int i = 0; i < N; i++) { chmin(latte[uf.find(i)], solve[i].first); } for(int i = 0; i < N; i++) { if(uf.find(i) == i) { ret += latte[i]; } } cout << ret << endl; }