#include "bits/stdc++.h" #define REP(i, n, N) for(ll i=(n); i<(N); i++) #define RREP(i, n, N) for(ll i=(N-1); i>=n; i--) #define CK(n, a, b) ((a)<=(n)&&(n)<(b)) #define ALL(v) (v).begin(),(v).end() #define MCP(a, b) memcpy(b,a,sizeof(b)) #define p(s) cout<<(s)<> typedef long long ll; using namespace std; const ll mod = 1e9 + 7; const ll inf = 1e18; const int MAX_N = 200210; int field[210][210]; int dx[4] = {0, 1, 0, -1}; int dy[4] = {-1, 0, 1, 0}; int H, W, Q; struct UnionFind { int par[MAX_N]; // 親ノードの番号 int deph[MAX_N]; // ノードの深さ int color[MAX_N]; vector neigh[MAX_N]; UnionFind(int n) { fill(par, par + MAX_N, -1); for (int i = 0; i < n; i++) { par[i] = i; deph[i] = 0; color[i] = field[i / 1000][i % 1000]; if(i%10000)neigh[i].push_back(i-1); if(i/10000)neigh[i].push_back(i-1000); /* 持っておくデータにおいて初期化が必要な場合 // istree[i] = true; */ } } int find(int x) { if (par[x] == x) { return x; } else { return par[x] = find(par[x]); } } void unite(int x, int y) { x = find(x); y = find(y); if (x == y) { /* 同じグループに属しているときの処理 // istree = false; */ return; } if (deph[x] < deph[y]) { par[x] = par[y]; color[x] = color[y]; copy(neigh[y].begin(), neigh[y].end(), back_inserter(neigh[x])); sort(neigh[y].begin(), neigh[y].end()); neigh[y].erase(unique(neigh[y].begin(), neigh[y].end()), neigh[y].end()); /* ルートをyとする時の処理 */ } else { par[y] = par[x]; color[y] = color[x]; copy(neigh[x].begin(), neigh[x].end(), back_inserter(neigh[y])); sort(neigh[x].begin(), neigh[x].end()); neigh[x].erase(unique(neigh[x].begin(), neigh[x].end()), neigh[x].end()); if (deph[x] == deph[y]) deph[x]++; /* ルートをxとする時の処理 */ } } bool same(int x, int y) { return find(x) == find(y); } void chcol(int x, int col) { int pa=find(x); set s; for(auto n:neigh[pa]){ int pa2=find(n); if(s.find(pa2)!=s.end()) continue; s.insert(pa2); } for(auto pa2:s){ unite(pa,pa2); } color[find(pa)] = col; } }; int main() { cin >> H >> W; REP(i, 0, H) REP(j, 0, W) cin >> field[i][j]; UnionFind uf(200210); bool visited[210][210]; REP(i, 0, H) REP(j, 0, W) visited[i][j] = false; queue> q; REP(i, 0, H) { REP(j, 0, W) { if (visited[i][j]) continue; int col = field[i][j]; q.push({i, j}); while (!q.empty()) { int cur_y = q.front().first; int cur_x = q.front().second; q.pop(); if (visited[cur_y][cur_x]) continue; visited[cur_y][cur_x] = true; REP(k, 0, 4) { //REP(k,0,8){ int next_y = cur_y + dy[k]; int next_x = cur_x + dx[k]; if (!CK(next_y, 0, H) || !CK(next_x, 0, W)) continue; if (field[next_y][next_x] != col) continue; if (!visited[next_y][next_x]) { //未到達の座標だけpush. q.push({next_y, next_x}); uf.unite(i * 1000 + j, next_y * 1000 + next_x); } } } } } cin >> Q; REP(q, 0, Q) { int y, x, c; cin >> y >> x >> c; y--; x--; int pa = uf.find(y * 1000 + x); if(uf.color[uf.find(y * 1000 + x)]!=c) uf.chcol(y * 1000 + x, c); } REP(i, 0, H) { REP(j, 0, W) { cout << uf.color[uf.find(i * 1000 + j)]; if (j < W - 1) cout << " "; } cout << endl; } return 0; }