#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class T>
using vec = vector<T>;
template <class T>
using vvec = vector<vec<T>>;
template <class T>
class Compress {
  int N;
  map<T, int> idx;
  map<int, T> value;
  vec<T> v;
  vec<T> cmp;

 public:
  Compress() {}
  void add(T x) { v.push_back(x); }
  void build() {
    for (auto& x : v) cmp.push_back(x);
    sort(cmp.begin(), cmp.end());
    cmp.erase(unique(cmp.begin(), cmp.end()), cmp.end());
    N = cmp.size();
    for (int i = 0; i < N; i++) idx[cmp[i]] = i;
  }
  int id(T val) { return idx[val]; }
  T val(int id) { return cmp[id]; }
  int size() { return N; }
};
class UnionFind {
 private:
  vec<int> p, s;
  int cnt;

 public:
  UnionFind() {}
  UnionFind(int N) : cnt(N), s(N, 1), p(N) { iota(p.begin(), p.end(), 0); }
  void init() {
    int N = s.size();
    cnt = N;
    fill(s.begin(), s.end(), 1);
    iota(p.begin(), p.end(), 0);
  }
  int find(int x) {
    if (p[x] == x)
      return x;
    else
      return p[x] = find(p[x]);
  }
  int unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y) return 0;
    if (s[x] > s[y]) swap(x, y);
    p[x] = y;
    s[y] += s[x];
    cnt--;
    return -1;
  }
  bool is_same_set(int x, int y) { return find(x) == find(y); }
  int size(int x) { return s[find(x)]; }
  int compnents_number() { return cnt; }
};
int main() {
  cin.tie(0);
  ios::sync_with_stdio(false);
  int N, M, Q;
  cin >> N >> M >> Q;
  vec<int> X(Q), Y(Q), C(Q);
  vec<int> delta(Q + 1);
  Compress<int> cmp;
  cmp.add(0);
  for (int i = 0; i < Q; i++) {
    cin >> X[i] >> Y[i] >> C[i];
    X[i]--;
    Y[i]--;
    cmp.add(C[i]);
  }
  cmp.build();
  int A = cmp.size();
  struct query {
    int x, y, id;
    query(int x, int y, int id) : x(x), y(y), id(id) {}
  };
  vvec<int> G(N, vec<int>(M));
  vvec<query> add(A), del(A);
  for (int i = 0; i < Q; i++) {
    if (G[X[i]][Y[i]] != C[i]) {
      del[cmp.id(G[X[i]][Y[i]])].emplace_back(X[i], Y[i], i);
      add[cmp.id(C[i])].emplace_back(X[i], Y[i], i);
      G[X[i]][Y[i]] = C[i];
    }
  }
  for (int i = 0; i < N; i++)
    for (int j = 0; j < M; j++) del[cmp.id(G[i][j])].emplace_back(i, j, Q);
  auto id = [&](int x, int y) { return x * M + y; };
  auto in = [&](int x, int y) { return 0 <= x && x < N && 0 <= y && y < M; };
  vec<int> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
  UnionFind uf(N * M);
  auto initialize = [&](vvec<int>& g) {
    uf.init();
    for (int i = 0; i < N; i++)
      for (int j = 0; j < M; j++) g[i][j] = 0;
  };
  auto update = [&](int x, int y, vvec<int>& g) {
    int d = 0;
    for (int k = 0; k < 4; k++) {
      int nx = x + dx[k], ny = y + dy[k];
      if (!in(nx, ny)) continue;
      if (g[nx][ny] == 1) d += uf.unite(id(x, y), id(nx, ny));
    }
    g[x][y] = 1;
    return d;
  };
  auto calc = [&](int c, vec<query>& q, int sign) {
    vvec<int> now = G;
    initialize(now);
    int n = q.size();
    for (int i = 0; i < n; i++) {
      auto [x, y, id] = q[i];
      delta[id] += update(x, y, now) * sign;
    }
  };
  for (int i = 0; i < A; i++) calc(i, add[i], 1);
  for (int i = 0; i < A; i++) {
    reverse(del[i].begin(), del[i].end());
    calc(i, del[i], -1);
  }
  int cur = 1;
  for (int i = 0; i < Q; i++) {
    cur += delta[i];
    cout << cur << "\n";
  }
}
