#include #include #include #define repeat(i,n) for (int i = 0; (i) < (n); ++(i)) typedef long long ll; using namespace std; struct union_find { vector tree; explicit union_find(size_t n) : tree(n, -1) {} bool is_root(int a) { return tree[a] < 0; } int find_root(int a) { return is_root(a) ? a : (tree[a] = find_root(tree[a])); } int tree_size(int a) { return - tree[find_root(a)]; } void union_tree(int a, int b) { a = find_root(a); b = find_root(b); if (a != b) { if (not (tree_size(a) < tree_size(b))) swap(a,b); tree[b] += tree[a]; tree[a] = b; } } bool is_connected(int a, int b) { return find_root(a) == find_root(b); } }; int main() { int h, w; cin >> h >> w; auto ix = [&](int y, int x) { return y*w + x; }; vector a(h * w); repeat (y,h) repeat (x,w) cin >> a[ix(y,x)]; union_find t(h * w); repeat (y,h) repeat (x,w) { if (y+1 < h and a[ix(y,x)] == a[ix(y+1,x)]) t.union_tree(ix(y,x), ix(y+1,x)); if (x+1 < w and a[ix(y,x)] == a[ix(y,x+1)]) t.union_tree(ix(y,x), ix(y,x+1)); } vector > g(h * w); repeat (y,h) repeat (x,w) { if (y+1 < h and a[ix(y,x)] != a[ix(y+1,x)]) { g[ix(y,x)].insert(ix(y+1,x)); g[ix(y+1,x)].insert(ix(y,x)); } if (x+1 < w and a[ix(y,x)] != a[ix(y,x+1)]) { g[ix(y,x)].insert(ix(y,x+1)); g[ix(y,x+1)].insert(ix(y,x)); } } int q; cin >> q; repeat (query,q) { int y, x, p; cin >> y >> x >> p; -- y; -- x; int i = t.find_root(ix(y,x)); if (a[i] == p) continue; a[i] = p; set s; for (int j : g[i]) { t.union_tree(i,j); for (int k : g[j]) s.insert(k); } for (int j : g[i]) s.erase(j); s.erase(i); int k = t.find_root(i); g[k] = s; for (int j : g[k]) g[j].insert(k); } repeat (y,h) { repeat (x,w) { if (x) cout << ' '; cout << a[t.find_root(ix(y,x))]; } cout << endl; } return 0; }