#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
struct Info {
  int a, b;
  Info operator+(const Info& B) const {
    return (Info){a + B.a, max(b + B.a, B.b)};
  }
};
struct Segment_Tree {
  const static int NODE = N << 2;
  bool setv[NODE];
  Info A[NODE];
  void pushdown(int o, int L, int R) {
    if (setv[o]) {
      set((o << 1), L, ((L + R) >> 1), L, R),
          set((o << 1 | 1), ((L + R) >> 1) + 1, R, L, R);
      setv[o] = 0;
    }
  }
  void modify(int o, int L, int R, int x, Info w) {
    if (L == R)
      A[o] = w;
    else {
      pushdown(o, L, R);
      x <= ((L + R) >> 1) ? modify((o << 1), L, ((L + R) >> 1), x, w)
                          : modify((o << 1 | 1), ((L + R) >> 1) + 1, R, x, w);
      A[o] = A[(o << 1)] + A[(o << 1 | 1)];
    }
  }
  void add(int o, int L, int R, int x) {
    if (L == R)
      A[o].a++, A[o].b++;
    else {
      pushdown(o, L, R);
      x <= ((L + R) >> 1) ? add((o << 1), L, ((L + R) >> 1), x)
                          : add((o << 1 | 1), ((L + R) >> 1) + 1, R, x);
      A[o] = A[(o << 1)] + A[(o << 1 | 1)];
    }
  }
  Info query(int o, int L, int R, int l, int r) {
    if (l <= L && R <= r)
      return A[o];
    else {
      pushdown(o, L, R);
      if (r <= ((L + R) >> 1))
        return query((o << 1), L, ((L + R) >> 1), l, r);
      else if (l > ((L + R) >> 1))
        return query((o << 1 | 1), ((L + R) >> 1) + 1, R, l, r);
      else
        return query((o << 1), L, ((L + R) >> 1), l, r) +
               query((o << 1 | 1), ((L + R) >> 1) + 1, R, l, r);
    }
  }
  void set(int o, int L, int R, int l, int r) {
    if (l <= L && R <= r)
      setv[o] = true, A[o] = (Info){L - R - 1, 0};
    else {
      if (l <= ((L + R) >> 1)) set((o << 1), L, ((L + R) >> 1), l, r);
      if (r > ((L + R) >> 1)) set((o << 1 | 1), ((L + R) >> 1) + 1, R, l, r);
      A[o] = A[(o << 1)] + A[(o << 1 | 1)];
    }
  }
} T;
int n, q;
int fa[N], sz[N], son[N], id[N];
vector<int> G[N];
void DFS_init(int o) {
  sz[o] = 1;
  for (int v : G[o]) {
    DFS_init(v);
    sz[o] += sz[v];
    if (sz[v] > sz[son[o]]) son[o] = v;
  }
}
int dfn[N], rdfn[N], top[N], clk;
void DFS_decompose(int o) {
  top[o] = son[fa[o]] == o ? top[fa[o]] : o;
  dfn[o] = ++clk;
  if (son[o]) DFS_decompose(son[o]);
  for (int v : G[o]) {
    if (v == son[o]) continue;
    DFS_decompose(v);
  }
  rdfn[o] = clk;
}
int getf(int o) {
  Info ret = (Info){0, 0};
  while (o) {
    int f = top[o];
    ret = T.query(1, 1, n, dfn[f], dfn[o]) + ret;
    o = fa[f];
  }
  return max(ret.a, ret.b);
}
int main() {
  scanf("%d%d", &n, &q);
  for (int i = 2; i <= n; i++) scanf("%d", &fa[i]), G[fa[i]].push_back(i);
  DFS_init(1);
  DFS_decompose(1);
  T.set(1, 1, n, 1, n);
  while (q--) {
    int op, v;
    scanf("%d%d", &op, &v);
    if (op == 1)
      T.add(1, 1, n, dfn[v]);
    else if (op == 2) {
      int w = v == 1 ? 0 : getf(fa[v]);
      T.modify(1, 1, n, dfn[v], (Info){-max(w, 1), 0});
      if (dfn[v] < rdfn[v]) T.set(1, 1, n, dfn[v] + 1, rdfn[v]);
    } else {
      puts(getf(v) > 0 ? "black" : "white");
    }
  }
  return 0;
}
