#include <bits/stdc++.h>
using namespace std;
vector<string> _split(const string& s, char c) {
  vector<string> v;
  stringstream ss(s);
  string x;
  while (getline(ss, x, c)) v.emplace_back(x);
  return v;
}
void _print(vector<string>::iterator) {}
template <typename T, typename... Args>
void _print(vector<string>::iterator it, T a, Args... args) {
  string name = it->substr((*it)[0] == ' ', it->length());
  if (isalpha(name[0]))
    cerr << name << " = " << a << " ";
  else
    cerr << name << " ";
  _print(++it, args...);
}
const long long int INF = (long long int)1e18;
bool is_in(int l, int r, int a, int b) { return a <= l && r <= b; }
bool not_inter(int l, int r, int a, int b) { return l > b || r < a; }
struct Tree {
  int pow2;
  vector<long long int> min_val;
  vector<long long int> max_val;
  vector<long long int> flag;
  Tree(int size = 1) {
    pow2 = 1;
    while (pow2 < size) pow2 *= 2;
    min_val.resize(pow2 * 2);
    max_val.resize(pow2 * 2);
    flag.resize(pow2 * 2);
    for (int i = 0; i < pow2 * 2; i++) {
      min_val[i] = 0;
      max_val[i] = 0;
    }
  }
  void add(int a, int b, long long int val) { add(1, 0, pow2 - 1, a, b, val); }
  void apply(int v, long long int x) {
    flag[v] += x;
    min_val[v] += x;
    max_val[v] += x;
  }
  void push(int v) {
    if (v < pow2) {
      long long int f = flag[v];
      apply(v * 2, f);
      apply(v * 2 + 1, f);
    }
    flag[v] = 0;
  }
  void update(int v) {
    min_val[v] = min(min_val[v * 2], min_val[v * 2 + 1]);
    max_val[v] = max(max_val[v * 2], max_val[v * 2 + 1]);
  }
  void add(int v, int l, int r, int a, int b, long long int val) {
    push(v);
    if (not_inter(l, r, a, b)) return;
    if (is_in(l, r, a, b)) {
      apply(v, val);
      return;
    }
    int m = (l + r) / 2;
    add(v * 2, l, m, a, b, val);
    add(v * 2 + 1, m + 1, r, a, b, val);
    update(v);
  }
  long long int get_min(int a, int b) { return get_min(1, 0, pow2 - 1, a, b); }
  long long int get_min(int v, int l, int r, int a, int b) {
    push(v);
    if (not_inter(l, r, a, b)) return INF;
    if (is_in(l, r, a, b)) return min_val[v];
    int m = (l + r) / 2;
    return min(get_min(v * 2, l, m, a, b), get_min(v * 2 + 1, m + 1, r, a, b));
  }
  long long int get_max(int a, int b) { return get_max(1, 0, pow2 - 1, a, b); }
  long long int get_max(int v, int l, int r, int a, int b) {
    push(v);
    if (not_inter(l, r, a, b)) return -INF;
    if (is_in(l, r, a, b)) return max_val[v];
    int m = (l + r) / 2;
    return max(get_max(v * 2, l, m, a, b), get_max(v * 2 + 1, m + 1, r, a, b));
  }
  void remove(int a) { remove(1, 0, pow2 - 1, a); }
  void remove(int v, int l, int r, int a) {
    push(v);
    if (l == r) {
      min_val[v] = INF;
      max_val[v] = -INF;
      return;
    }
    int m = (l + r) / 2;
    if (a <= m)
      remove(v * 2, l, m, a);
    else
      remove(v * 2 + 1, m + 1, r, a);
    update(v);
  }
  long long int get(int a) { return get_min(a, a); }
};
const int N = (int)2e5;
int n, q;
long long int t[N];
int f[N];
int qa[N], qb[N], qc[N];
int cur_deg[N];
int max_deg[N];
Tree tree[N];
int ptr[N];
int pos_in_tree[N];
long long int old_small[N], old_big[N];
long long int min_in_v[N], max_in_v[N];
bool cmp_max(int a, int b) {
  if (max_in_v[a] != max_in_v[b]) return max_in_v[a] > max_in_v[b];
  return a > b;
}
bool cmp_min(int a, int b) {
  if (min_in_v[a] != min_in_v[b]) return min_in_v[a] < min_in_v[b];
  return a < b;
}
set<int, decltype(&cmp_min)> s_by_min(&cmp_min);
set<int, decltype(&cmp_max)> s_by_max(&cmp_max);
void scan() {
  scanf("%d%d", &n, &q);
  for (int i = 0; i < n; i++) scanf("%lld", &t[i]);
  for (int i = 0; i < n; i++) {
    scanf("%d", &f[i]);
    f[i]--;
  }
  for (int i = 0; i < q; i++) {
    scanf("%d", &qa[i]);
    if (qa[i] == 1) {
      scanf("%d%d", &qb[i], &qc[i]);
      qb[i]--;
      qc[i]--;
    } else if (qa[i] == 2) {
      scanf("%d", &qb[i]);
      qb[i]--;
    }
  }
}
void calc_max_deg() {
  for (int i = 0; i < n; i++) max_deg[f[i]]++;
  for (int i = 0; i < q; i++)
    if (qa[i] == 1) max_deg[qc[i]]++;
}
void add_to_v(int v, long long int x) {
  tree[f[v]].add(pos_in_tree[v], pos_in_tree[v], x);
}
int timer = 1;
int used[N];
void add_update(int v) {
  used[v] = timer;
  long long int k = cur_deg[v];
  long long int sm = t[v] / (k + 2);
  long long int bg = t[v] - sm * (k + 1);
  tree[v].add(0, ptr[v] - 1, sm);
  add_to_v(v, bg);
  add_to_v(f[v], sm);
  old_small[v] = sm;
  old_big[v] = bg;
}
void rem_update(int v) {
  tree[v].add(0, ptr[v] - 1, -old_small[v]);
  add_to_v(v, -old_big[v]);
  add_to_v(f[v], -old_small[v]);
  old_small[v] = 0;
  old_big[v] = 0;
}
void rem_from_s(int v) {
  s_by_min.erase(v);
  s_by_max.erase(v);
}
void add_to_s(int v) {
  s_by_min.insert(v);
  s_by_max.insert(v);
}
void update_min_max(int v) {
  min_in_v[v] = tree[v].get_min(0, ptr[v] - 1);
  max_in_v[v] = tree[v].get_max(0, ptr[v] - 1);
}
void init_trees() {
  for (int i = 0; i < n; i++) tree[i] = Tree(max_deg[i]);
  for (int i = 0; i < n; i++) {
    cur_deg[f[i]]++;
    pos_in_tree[i] = ptr[f[i]]++;
  }
  for (int i = 0; i < n; i++) add_update(i);
  for (int i = 0; i < n; i++) {
    update_min_max(i);
    add_to_s(i);
  }
}
void change(int v, int new_f) {
  timer++;
  int old_f = f[v];
  int new_f2 = f[new_f];
  int old_f2 = f[old_f];
  int new_f3 = f[new_f2];
  int old_f3 = f[old_f2];
  rem_from_s(old_f);
  rem_from_s(v);
  rem_from_s(new_f);
  rem_from_s(new_f2);
  rem_from_s(old_f2);
  rem_from_s(new_f3);
  rem_from_s(old_f3);
  rem_update(old_f);
  rem_update(v);
  rem_update(new_f);
  cur_deg[old_f]--;
  long long int old_x = tree[old_f].get(pos_in_tree[v]);
  tree[old_f].remove(pos_in_tree[v]);
  f[v] = new_f;
  pos_in_tree[v] = ptr[new_f]++;
  tree[new_f].add(pos_in_tree[v], pos_in_tree[v], old_x);
  cur_deg[new_f]++;
  add_update(old_f);
  add_update(v);
  add_update(new_f);
  update_min_max(old_f);
  update_min_max(v);
  update_min_max(new_f);
  update_min_max(new_f2);
  update_min_max(old_f2);
  update_min_max(new_f3);
  update_min_max(old_f3);
  add_to_s(old_f);
  add_to_s(v);
  add_to_s(new_f);
  add_to_s(new_f2);
  add_to_s(old_f2);
  add_to_s(new_f3);
  add_to_s(old_f3);
}
long long int get_val(int v) { return tree[f[v]].get(pos_in_tree[v]); }
long long int get_max_val() {
  int v = *s_by_max.begin();
  return max_in_v[v];
}
long long int get_min_val() {
  int v = *s_by_min.begin();
  return min_in_v[v];
}
int main() {
  scan();
  calc_max_deg();
  init_trees();
  for (int i = 0; i < q; i++) {
    if (qa[i] == 1) {
      int v = qb[i];
      int new_f = qc[i];
      change(v, new_f);
    } else if (qa[i] == 2) {
      int v = qb[i];
      long long int ans = get_val(v);
      printf("%lld\n", ans);
    } else {
      long long int min_val = get_min_val();
      long long int max_val = get_max_val();
      printf("%lld %lld\n", min_val, max_val);
    }
  }
  return 0;
}
