#include <bits/stdc++.h>
using namespace std;
inline char nc() {
  static char buf[100000], *l = buf, *r = buf;
  return l == r && (r = (l = buf) + fread(buf, 1, 100000, stdin), l == r)
             ? EOF
             : *l++;
}
template <class T>
void read(T &x) {
  x = 0;
  int f = 1, ch = nc();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = nc();
  }
  while (ch >= '0' && ch <= '9') {
    x = x * 10 - '0' + ch;
    ch = nc();
  }
  x *= f;
}
const int maxk = 12 + 5;
const int maxn = 1e5 + 5;
const int maxs = 4096;
const int maxnode = 100012 + 5;
int bin[maxk];
int n, k, q, a[maxk][maxn];
pair<int, int> ord[maxn];
bitset<maxs> val[maxnode];
void init() {
  bin[0] = 1;
  for (int i = 1; i < maxk; ++i) {
    bin[i] = bin[i - 1] << 1;
  }
}
int main() {
  init();
  read(n), read(k), read(q);
  for (int i = 1; i <= k; ++i) {
    for (int j = 1; j <= n; ++j) {
      read(a[i][j]);
    }
  }
  for (int i = 1; i <= k; ++i) {
    for (int s = 0; s < bin[k]; ++s) {
      if (s & bin[i - 1]) val[i][s] = 1;
    }
  }
  int cnt = k;
  for (int qury = 1; qury <= q; ++qury) {
    int op;
    read(op);
    int x, y;
    read(x), read(y);
    if (op == 1) {
      val[++cnt] = val[x] | val[y];
    } else if (op == 2) {
      val[++cnt] = val[x] & val[y];
    } else {
      for (int i = 1; i <= k; ++i) {
        ord[i] = pair<int, int>(a[i][y], i);
      }
      sort(ord + 1, ord + k + 1);
      int s = 0;
      for (int i = k; i >= 1; --i) {
        s |= bin[ord[i].second - 1];
        if (val[x][s]) {
          printf("%d\n", ord[i].first);
          break;
        }
      }
    }
  }
  return 0;
}
