2 5 10
2 2
1 1
1 4
2 1
1 2
1 5
2 4
2 5
1 3
2 3
 2 2 2
1 1
2 2
 3 3 9
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
 7 5 35
5 3
3 5
1 1
2 5
6 4
7 2
5 1
3 4
6 5
7 3
4 1
2 2
4 2
2 4
4 3
3 3
6 1
1 2
4 5
1 3
2 1
5 5
7 5
7 1
6 2
1 4
1 5
3 2
4 4
5 2
2 3
6 3
7 4
5 4
3 1
 1 5 4
1 1
1 2
1 4
1 5
 1 1 1
1 1
 5 7 21
4 4
4 5
5 5
5 6
5 7
5 1
5 2
4 2
3 2
3 1
3 7
3 6
2 6
1 6
1 7
1 1
1 2
1 3
1 4
2 4
3 4
 2 1 1
1 1
 2 2 4
2 1
1 1
1 2
2 2
 3000 3000 1
2222 738
 5 7 35
1 2
2 3
5 1
5 7
4 4
5 3
3 1
2 6
4 5
2 7
4 1
2 1
2 2
1 7
5 6
3 6
4 6
1 6
1 1
3 3
3 4
4 2
2 5
5 5
3 5
2 4
1 5
1 3
4 3
5 4
1 4
3 7
4 7
3 2
5 2
 5 4 1
4 1
 3 4 12
2 3
3 2
2 2
2 1
1 2
3 1
1 4
1 3
3 3
2 4
3 4
1 1
 3 3 3
1 1
2 2
3 3

8
 1
 6
 26
 4
 0
 20
 0
 2
 1
 28
 1
 9
 3

#include <bits/stdc++.h>
using namespace std;
template <class T, size_t D>
struct vec : vector<vec<T, D - 1>> {
  template <class... Args>
  vec(size_t n = 0, Args... args)
      : vector<vec<T, D - 1>>(n, vec<T, D - 1>(args...)) {}
};
template <class T>
struct vec<T, 1> : vector<T> {
  template <class... Args>
  vec(Args... args) : vector<T>(args...) {}
};
template <class T>
inline bool Minimize(T& a, const T& b) {
  return a > b ? a = b, true : false;
}
template <class T>
inline bool Maximize(T& a, const T& b) {
  return a < b ? a = b, true : false;
}
inline int Next(int i, int n) { return i == n - 1 ? 0 : i + 1; }
inline int Prev(int i, int n) { return !i ? n - 1 : i - 1; }
mt19937 rng(static_cast<uint32_t>(
    chrono::steady_clock::now().time_since_epoch().count()));
struct DSU {
  int n_sets;
  vec<int, 1> parents, cardinalities;
  DSU(int t_n_sets)
      : n_sets(t_n_sets), parents(n_sets), cardinalities(n_sets, 1) {
    iota((parents).begin(), (parents).end(), 0);
  }
  int Parent(int i) {
    return i == parents[i] ? i : parents[i] = Parent(parents[i]);
  }
  bool SameSet(int i, int j) { return Parent(i) == Parent(j); }
  bool Unite(int i, int j) {
    i = Parent(i);
    j = Parent(j);
    if (i == j) {
      return false;
    }
    if (cardinalities[i] > cardinalities[j]) {
      swap(i, j);
    }
    --n_sets;
    parents[i] = j;
    cardinalities[j] += cardinalities[i];
    return true;
  }
};
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  int n_rows, n_columns, n;
  cin >> n_rows >> n_columns >> n;
  auto Get = [&](const tuple<int, int, int>& a, const tuple<int, int, int>& b) {
    if (get<0>(a) == 2 || get<0>(b) == 2) {
      return tuple<int, int, int>{2, -1, -1};
    }
    vec<pair<int, int>, 1> ranges;
    if (get<0>(a)) {
      ranges.emplace_back(get<1>(a), n_columns - 1);
      ranges.emplace_back(0, get<2>(a));
    } else if (~get<1>(a)) {
      ranges.emplace_back(get<1>(a), get<2>(a));
    }
    if (get<0>(b)) {
      ranges.emplace_back(get<1>(b), n_columns - 1);
      ranges.emplace_back(0, get<2>(b));
    } else if (~get<1>(b)) {
      ranges.emplace_back(get<1>(b), get<2>(b));
    }
    sort((ranges).begin(), (ranges).end());
    if (!static_cast<int>((ranges).size())) {
      return tuple<int, int, int>{0, -1, -1};
    }
    vec<pair<int, int>, 1> ret;
    int i = -1;
    for (auto& range : ranges) {
      if (range.first > i) {
        if (static_cast<int>((ret).size())) {
          ret.back().second = i - 1;
        }
        ret.emplace_back(range.first, 0);
        i = range.second + 1;
      } else {
        Maximize(i, range.second + 1);
      }
    }
    ret.back().second = i - 1;
    if (static_cast<int>((ret).size()) == 1) {
      if (ret[0] == pair<int, int>{0, n_columns - 1}) {
        return tuple<int, int, int>{2, -1, -1};
      } else {
        return tuple<int, int, int>{0, ret[0].first, ret[0].second};
      }
    } else {
      return tuple<int, int, int>{1, ret[1].first, ret[0].second};
    }
  };
  auto Index = [&](int i, int j) { return i * n_columns + j; };
  vec<tuple<int, int, int>, 1> ranges(n_rows * n_columns,
                                      tuple<int, int, int>{0, -1, -1});
  int answer = 0;
  vec<bool, 2> reclamated(n_rows, n_columns);
  DSU dsu(n_rows * n_columns);
  while (n--) {
    int x, y;
    cin >> x >> y;
    --x;
    --y;
    tuple<int, int, int> tmp_range{0, -1, -1};
    for (int i = -1; i <= 1; ++i) {
      for (int j = -1; j <= 1; ++j) {
        int next_x = x + i, next_y = y + j;
        if (next_x < 0 || next_x >= n_rows) {
          continue;
        }
        if (next_y < 0) {
          next_y = n_columns - 1;
        } else if (next_y >= n_columns) {
          next_y = 0;
        }
        if (reclamated[next_x][next_y]) {
          tmp_range = Get(tmp_range, ranges[dsu.Parent(Index(next_x, next_y))]);
          if (!~j) {
            tmp_range = Get(tmp_range, tuple<int, int, int>{0, next_y, next_y});
          } else if (j) {
            tmp_range = Get(tmp_range, tuple<int, int, int>{0, y, y});
          }
        }
      }
    }
    if (get<0>(tmp_range) != 2) {
      ++answer;
      reclamated[x][y] = true;
      int parent = Index(x, y);
      for (int i = -1; i <= 1; ++i) {
        for (int j = -1; j <= 1; ++j) {
          int next_x = x + i, next_y = y + j;
          if (next_x < 0 || next_x >= n_rows) {
            continue;
          }
          if (next_y < 0) {
            next_y = n_columns - 1;
          } else if (next_y >= n_columns) {
            next_y = 0;
          }
          if (reclamated[next_x][next_y]) {
            dsu.Unite(parent, dsu.Parent(Index(next_x, next_y)));
            parent = dsu.parents[parent];
          }
        }
      }
      ranges[parent] = tmp_range;
    }
  }
  cout << answer << '\n';
  return 0;
}
