#include using namespace std; #define ALL(x) begin(x),end(x) #define rep(i,n) for(int i=0;i<(n);i++) #define debug(v) cout<<#v<<":";for(auto x:v){cout<bool chmax(T &a,const T &b){if(abool chmin(T &a,const T &b){if(b ostream &operator<<(ostream &os,const vector&v){ for(int i=0;i<(int)v.size();i++) os< istream &operator>>(istream &is,vector&v){ for(T &x:v)is>>x; return is; } struct UnionFind{ int con; vector par,siz; UnionFind(int n):con(n),par(n),siz(n,1){ iota(begin(par),end(par),0); } int root(int x){ return (par[x]==x?x:(par[x]=root(par[x]))); } bool sameroot(int x,int y){ return root(x)==root(y); } bool unite(int x,int y){ x=root(x);y=root(y); if(x==y) return false; if(siz[x]>n>>d>>w; UnionFind ufd(n),ufw(n); vector> gd(n),gw(n); rep(i,d){ int u,v;cin>>u>>v;u--,v--; gd[u].push_back(v); gd[v].push_back(u); ufd.unite(u,v); } rep(i,w){ int u,v;cin>>u>>v;u--,v--; gw[u].push_back(v); gw[v].push_back(u); } ll res=0; rep(i,n)if(ufd.root(i)==i){ ll k=ufd.size(i); res+=k*k; } vector check(n,false); rep(i,n)if(not check[i]){ map cnt; function dfs=[&](int cur){ cnt[ufd.root(cur)]++; for(auto to:gw[cur])if(not check[to]){ check[to]=true; dfs(to); } }; check[i]=true; dfs(i); ll sum=0; for(auto [_,v]:cnt) sum+=v; for(auto [par,v]:cnt){ res+=(ll)(sum-v)*ufd.size(par); } } res-=n; cout<