#define _USE_MATH_DEFINES #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; class UnionFindTree { private: int n; int groupNum; // グループの数 vector parent; // 親ノード vector rank; // 木の高さの上限 vector num; // グループの要素数 int find(int i){ if(parent[i] == i) return i; else return parent[i] = find(parent[i]); } public: UnionFindTree(int n){ // コンストラクタ this->n = n; groupNum = n; parent.resize(n); for(int i=0; i class EdgeBase { public: int to; T cost; EdgeBase(){}; EdgeBase(int to0, T cost0){to = to0; cost = cost0;} }; typedef EdgeBase Edge; template class LowestCommonAncestor { private: vector > to; // ダブリング先のノード vector depth; // 根からの深さ vector dist; // 根からの距離 int climb(int curr, int len) { int i = 0; while(len > 0){ if(len % 2 == 1) curr = to[curr][i]; len /= 2; ++ i; } return curr; } public: LowestCommonAncestor(const vector > >& edges, int root) { int n = edges.size(); to.assign(n, vector()); dist.assign(n, 0); depth.assign(n, 0); queue > q; q.push(make_pair(root, -1)); int cnt = 0; while(!q.empty()){ int m = q.size(); while(--m >= 0){ int curr, prev; tie(curr, prev) = q.front(); q.pop(); if(prev != -1){ to[curr].push_back(prev); int j = prev; for(unsigned k=0; k& e : edges[curr]){ if(e.to != prev){ depth[e.to] = depth[curr] + 1; dist[e.to] = dist[curr] + e.cost; q.push(make_pair(e.to, curr)); } } } ++ cnt; } } // 2つのノードの最小共通祖先を取得 int getAncestor(int a, int b) { int diff = depth[a] - depth[b]; if(diff < 0) b = climb(b, -diff); else a = climb(a, diff); if(a == b) return a; for(int i=to[a].size()-1; i>=0; --i){ if(i < (int)to[a].size() && to[a][i] != to[b][i]){ a = to[a][i]; b = to[b][i]; } } return to[a][0]; } // ノードの深さを取得 int getDepth(int a) { return depth[a]; } // 2つのノードの距離を取得 T getDist(int a, int b) { int c = getAncestor(a, b); return dist[a] + dist[b] - dist[c] * 2; } }; const int INF = INT_MAX / 4; void dfs1(const vector >& edges, const vector& cnt, int curr, int prev, vector >& v) { v[curr] = make_pair(cnt[curr], 0); for(const auto& e : edges[curr]){ int next = e.to; if(next == prev) continue; dfs1(edges, cnt, next, curr, v); v[curr].first += v[next].first; v[curr].second += v[next].second + v[next].first; } } long long dfs2(const vector >& edges, int curr, int prev, const vector >& v, pair p) { pair sum = v[curr]; sum.first += p.first; sum.second += p.second + p.first; long long ans = sum.second; for(const auto& e : edges[curr]){ int next = e.to; if(next == prev) continue; pair p2 = sum; p2.first -= v[next].first; p2.second -= v[next].second + v[next].first; ans = min(ans, dfs2(edges, next, curr, v, p2)); } return ans; } int main() { int n, m, q; cin >> n >> m >> q; vector > edges(n+1); UnionFindTree uft(n+1); for(int i=0; i> u >> v; edges[u].push_back(Edge(v, 1)); edges[v].push_back(Edge(u, 1)); uft.unite(u, v); } for(int i=1; i<=n; ++i){ if(!uft.same(0, i)){ edges[0].push_back(Edge(i, INF)); uft.unite(0, i); } } LowestCommonAncestor lca(edges, 0); vector cnt(n+1, 0); long long ans = 0; for(int i=0; i> a >> b; int dist = lca.getDist(a, b); if(dist < INF){ ans += dist; } else{ ++ cnt[a]; ++ cnt[b]; } } vector > v(n+1, make_pair(-1, -1)); for(int i=1; i<=n; ++i){ if(v[i].first != -1) continue; dfs1(edges, cnt, i, -1, v); ans += dfs2(edges, i, -1, v, make_pair(0, 0)); } cout << ans << endl; return 0; }