#include #include #include #include #include #include #include #include #include using namespace std; typedef long long ll; #define int long long #define double long double typedef vector VI; typedef pair pii; typedef vector VP; typedef vector VS; typedef priority_queue PQ; templatebool chmax(T &a, const T &b) { if (a < b) { a = b; return 1; } return 0; } templatebool chmin(T &a, const T &b) { if (b < a) { a = b; return 1; } return 0; } #define fore(i,a) for(auto &i:a) #define REP(i,n) for(int i=0;i, greater > q2; int N, D, W; vectorG; bool vis[200010]; struct UnionFind { VI par, s; UnionFind(int N) :par(N), s(N) { REP(i, N)par[i] = i; REP(i, N)s[i] = 1; } int root(int x) { if (par[x] == x)return x; return par[x] = root(par[x]); } void unite(int x, int y) { int rx = root(x); int ry = root(y); if (rx == ry)return; if (!(same(x, y)))s[ry] += s[rx]; par[rx] = ry; } bool same(int x, int y) { int rx = root(x); int ry = root(y); return rx == ry; } int size(int x) { return s[root(x)]; } }; signed main() { cin.tie(0); ios::sync_with_stdio(false); cin >> N >> D >> W; G.resize(N); UnionFind X(N), Y(N); REP(i, D) { int a, b; cin >> a >> b; a--, b--; X.unite(a, b); G[a].push_back(b); G[b].push_back(a); } REP(i, W) { int a, b; cin >> a >> b; a--, b--; Y.unite(a, b); } int ans = 0; REP(i, N) { if (vis[i])continue; VI tmp; queueQ; bool F[200010] = { false }; Q.push(i); vis[i] = 1; while (!Q.empty()) { int now = Q.front(); Q.pop(); tmp.push_back(now); fore(to, G[now]) { if (!vis[to]) { Q.push(to); vis[to] = 1; } } } int cnt = 0; fore(j, tmp) { //cout << j << " "; if (!F[Y.root(j)]) { F[Y.root(j)] = 1; cnt += Y.size(j); } } //cout << cnt << endl; ans += (int)tmp.size()*cnt; ans -= (int)tmp.size(); } cout << ans << endl; return 0; }