#include <bits/stdc++.h>
long long a[100][100];
using namespace std;
struct DynamicDisjointSetDS {
  std::unordered_map<int, int> parent, degree;
  int N;
  DynamicDisjointSetDS(int n) { N = n; }
  int getParent(int vertex) {
    if (parent.find(vertex) != parent.end()) {
      if (parent[vertex] != vertex) {
        parent[vertex] = getParent(parent[vertex]);
        return parent[vertex];
      }
    } else {
      parent.insert(make_pair(vertex, vertex));
      degree.insert(make_pair(vertex, 1));
    }
    return vertex;
  }
  void Union(int vertexA, int vertexB) {
    int x = getParent(vertexA);
    int y = getParent(vertexB);
    if (x == y) return;
    if (degree[x] > degree[y]) {
      parent[y] = x;
      degree[x] = degree[x] + degree[y];
    } else {
      parent[x] = y;
      degree[y] = degree[y] + degree[x];
    }
  }
  int GetTotalComponent() {
    unordered_set<int> total;
    for (auto itr = parent.begin(); itr != parent.end(); itr++) {
      total.insert(getParent(itr->first));
    }
    return N - parent.size() + total.size();
  }
};
int main() {
  using namespace std;
  long long n, m, q;
  cin >> n >> m >> q;
  unordered_set<long long> s, s2;
  for (long long i = 1; i <= n; i++) {
    s.insert(i);
  }
  for (long long i = 1; i <= m; i++) {
    s2.insert(i);
  }
  DynamicDisjointSetDS ds(m + 1);
  vector<vector<long long>> v(m + 1);
  while (q--) {
    long long r, c;
    cin >> r >> c;
    v[c].push_back(r);
    s.erase(r);
    s2.erase(c);
  }
  for (vector<long long> v2 : v) {
    for (long long i = 1; i < v2.size(); i++) {
      ds.Union(v2[i], v2[i - 1]);
    }
  }
  unordered_set<long long> sc;
  for (long long i = 1; i <= n; i++) {
    sc.insert(ds.getParent(i));
  }
  cout << (s2.size() + sc.size() - 1) << endl;
}
