#include <bits/stdc++.h>
using namespace std;
class DisjointSet {
 public:
  DisjointSet(int n) : N(n), sz(n), cnts(n, 1), pars(n, 0) {
    iota(pars.begin(), pars.end(), 0);
  }
  void reset() {
    sz = N;
    fill(cnts.begin(), cnts.end(), 1);
    iota(pars.begin(), pars.end(), 0);
  }
  int find(int x) {
    if (pars[x] == x) {
      return x;
    }
    return pars[x] = find(pars[x]);
  }
  bool merge(int x, int y) {
    x = find(x), y = find(y);
    if (x == y) {
      return false;
    }
    --sz;
    if (cnts[x] > cnts[y]) {
      swap(x, y);
    }
    pars[x] = y;
    cnts[y] += cnts[x];
    return true;
  }
  int size() { return sz; }
  int count(int x) { return cnts[find(x)]; }

 private:
  int N;
  int sz;
  vector<int> cnts;
  vector<int> pars;
};
class Solution {
 public:
  vector<int> solve(int n, int m, vector<vector<int>>& queries) {
    int q = queries.size();
    vector<int> res(q, 0);
    vector<vector<int>> M(n, vector<int>(m, 0));
    DisjointSet ds(n * m);
    DisjointSet ds2(n * m);
    vector<int> oldValue(q, 0);
    vector<int> X{0, 1, 0, -1};
    vector<int> Y{1, 0, -1, 0};
    for (int i = 0; i < q; ++i) {
      int l = i;
      int x = queries[i][0], y = queries[i][1];
      oldValue[i] = M[x][y];
      M[x][y] = queries[i][2];
      int color = queries[i][2];
      while (i + 1 < q && queries[i + 1][2] == queries[i][2]) {
        ++i;
        x = queries[i][0];
        y = queries[i][1];
        oldValue[i] = M[x][y];
        M[x][y] = queries[i][2];
      }
      int r = i;
      ds.reset();
      ds2.reset();
      for (int x = 0; x < n; ++x) {
        for (int y = 0; y < m; ++y) {
          if (x + 1 < n && M[x][y] == M[x + 1][y]) {
            if (M[x][y] == color) {
            } else {
              ds.merge(x * m + y, (x + 1) * m + y);
            }
          }
          if (y + 1 < m && M[x][y] == M[x][y + 1]) {
            if (M[x][y] == color) {
            } else {
              ds.merge(x * m + y, x * m + y + 1);
            }
          }
        }
      }
      int cn = 0;
      for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
          if (M[i][j] == color) {
            ++cn;
          }
        }
      }
      for (int j = r; j >= l; --j) {
        res[j] += ds.size() - cn;
        int x = queries[j][0];
        int y = queries[j][1];
        M[x][y] = oldValue[j];
        if (M[x][y] != color) {
          --cn;
        }
        for (int k = 0; k < X.size(); ++k) {
          int nx = x + X[k];
          int ny = y + Y[k];
          if (nx >= 0 && nx < n && ny >= 0 && ny < m) {
            if (M[x][y] == M[nx][ny] && M[x][y] != color) {
              ds.merge(x * m + y, nx * m + ny);
            }
          }
        }
      }
      cn = n * m;
      for (int j = l; j <= r; ++j) {
        int x = queries[j][0];
        int y = queries[j][1];
        if (M[x][y] != color) {
          --cn;
        }
        M[x][y] = color;
        for (int k = 0; k < X.size(); ++k) {
          int nx = x + X[k];
          int ny = y + Y[k];
          if (nx >= 0 && nx < n && ny >= 0 && ny < m && M[nx][ny] == color) {
            ds2.merge(x * m + y, nx * m + ny);
          }
        }
        res[j] += ds2.size() - cn;
      }
    }
    return res;
  }
};
int main(int argc, char** argv) {
  ios::sync_with_stdio(false);
  cin.tie(0);
  Solution sol;
  int n, m, q;
  cin >> n >> m >> q;
  vector<vector<int>> queries;
  queries.reserve(q);
  for (int i = 0; i < q; ++i) {
    int x, y, c;
    cin >> x >> y >> c;
    --x, --y;
    queries.emplace_back(vector<int>{x, y, c});
  }
  auto res = sol.solve(n, m, queries);
  for (auto r : res) {
    cout << r << "\n";
  }
  return 0;
}
