Abendsen assigned a mission to Juliana. In this mission, Juliana has a rooted tree with n vertices. Vertex number 1 is the root of this tree. Each vertex can be either black or white. At first, all vertices are white. Juliana is asked to process q queries. Each query is one of three types:

  1. If vertex v is white, mark it as black; otherwise, perform this operation on all direct sons of v instead. 
  2. Mark all vertices in the subtree of v (including v) as white. 
  3. Find the color of the i-th vertex. 

<image> An example of operation "1 1" (corresponds to the first example test). The vertices 1 and 2 are already black, so the operation goes to their sons instead.

Can you help Juliana to process all these queries?

Input

The first line contains two integers n and q (2≤ n≤ 10^5, 1≤ q≤ 10^5) — the number of vertices and the number of queries.

The second line contains n-1 integers p_2, p_3, …, p_n (1≤ p_i<i), where p_i means that there is an edge between vertices i and p_i. 

Each of the next q lines contains two integers t_i and v_i (1≤ t_i≤ 3, 1≤ v_i≤ n) — the type of the i-th query and the vertex of the i-th query.

It is guaranteed that the given graph is a tree.

Output

For each query of type 3, print "black" if the vertex is black; otherwise, print "white".

Examples

Input

8 10
1 2 1 2 5 4 5
1 2
3 2
3 1
1 1
1 1
3 5
3 7
3 4
2 2
3 5


Output

black
white
black
white
black
white


Input

8 11
1 1 2 3 3 6 6
1 1
1 1
1 3
3 2
3 4
3 6
3 7
2 3
1 6
3 7
3 6


Output

black
white
black
white
white
black

Note

The first example is shown on the picture below.

<image>

The second example is shown on the picture below.

<image>
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m, fa[maxn], dep[maxn], size[maxn];
int root = 1, tot, pos[maxn], son[maxn], tid[maxn], top[maxn];
long long val[maxn];
vector<int> G[maxn];
struct Pair {
  int sum, mx;
  Pair() {
    sum = -INF;
    mx = -INF;
  }
  Pair(int _v1, int _v2) { sum = _v1, mx = _v2; }
} node[N << 2];
Pair operator+(Pair a, Pair b) {
  if (a.sum == -INF) return b;
  if (b.sum == -INF) return a;
  Pair tmp;
  tmp.sum = a.sum + b.sum;
  tmp.mx = max(b.mx, a.mx + b.sum);
  return tmp;
}
void dfs1(int x, int father, int depth) {
  fa[x] = father, dep[x] = depth;
  size[x] = 1;
  int max_size = 0;
  for (int i = 0; i < G[x].size(); i++) {
    if (G[x][i] != father) {
      dfs1(G[x][i], x, depth + 1);
      size[x] += size[G[x][i]];
      if (size[G[x][i]] > max_size) {
        max_size = size[G[x][i]];
        son[x] = G[x][i];
      }
    }
  }
}
void dfs2(int x, int root, int father) {
  tid[x] = ++tot, pos[tot] = x, top[x] = root;
  if (son[x]) {
    if (son[x] != father) dfs2(son[x], root, x);
  }
  for (int i = 0; i < G[x].size(); i++) {
    if (G[x][i] != father) {
      if (G[x][i] != son[x]) {
        dfs2(G[x][i], G[x][i], x);
      }
    }
  }
}
bool add[N << 2];
void Maintain(int rt) {
  node[rt] = node[rt << 1] + node[rt << 1 | 1];
  return;
}
void Pushdown(int rt, int l, int r) {
  if (add[rt] != 0) {
    node[rt] = Pair(-(r - l + 1), -1);
    if (l < r) {
      add[rt << 1] = 1;
      add[rt << 1 | 1] = 1;
    }
    add[rt] = 0;
  }
}
void build(int l, int r, int rt = 1) {
  if (l == r) {
    node[rt] = Pair(-1, -1);
    return;
  }
  int m = (l + r) >> 1;
  build(l, m, rt << 1);
  build(m + 1, r, rt << 1 | 1);
  Maintain(rt);
  return;
}
void update(int L, int R, int c, int d, int l, int r, int rt = 1) {
  Pushdown(rt, l, r);
  if (L > r || R < l) return;
  if (d == 1) {
    if (L <= l && r <= R && l == r) {
      node[rt].sum += c;
      node[rt].mx += c;
      return;
    }
  } else {
    if (L <= l && r <= R) {
      add[rt] = 1;
      Pushdown(rt, l, r);
      return;
    }
  }
  int m = (l + r) >> 1;
  update(L, R, c, d, l, m, rt << 1);
  update(L, R, c, d, m + 1, r, rt << 1 | 1);
  Maintain(rt);
  return;
}
Pair query(int L, int R, int l, int r, int rt = 1) {
  Pushdown(rt, l, r);
  if (L > r || R < l) return Pair();
  if (L <= l && r <= R) {
    return node[rt];
  }
  int m = (l + r) >> 1;
  return query(L, R, l, m, rt << 1) + query(L, R, m + 1, r, rt << 1 | 1);
}
int lca(int x, int y) {
  int fx = top[x], fy = top[y];
  while (fx != fy) {
    if (dep[fx] > dep[fy])
      x = fa[fx], fx = top[x];
    else
      y = fa[fy], fy = top[y];
  }
  if (dep[x] >= dep[y]) return y;
  return x;
}
void solve_add(int u, int v, long long val) {
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) {
      swap(u, v);
    }
    update(tid[top[u]], tid[u], val, 1, 1, n);
    u = fa[top[u]];
  }
  if (tid[u] > tid[v]) {
    swap(u, v);
  }
  update(tid[u], tid[v], val, 1, 1, n);
}
Pair solve_query(int u, int v) {
  Pair sum = Pair();
  while (top[u] != top[v]) {
    if (dep[top[u]] < dep[top[v]]) {
      swap(u, v);
    }
    sum = query(tid[top[u]], tid[u], 1, n) + sum;
    u = fa[top[u]];
  }
  if (tid[u] > tid[v]) {
    swap(u, v);
  }
  sum = query(tid[u], tid[v], 1, n) + sum;
  return sum;
}
void update_subtree(int v, long long val) {
  if (v == root) {
    update(1, n, val, -1, 1, n);
    return;
  }
  if (tid[v] > tid[root] || tid[v] + size[v] - 1 < tid[root] + size[root] - 1) {
    update(tid[v], tid[v] + size[v] - 1, val, -1, 1, n);
    return;
  }
  int u = lca(v, root);
  update(1, tid[u] - 1, val, -1, 1, n),
      update(tid[u] + size[u], n, val, -1, 1, n);
}
int main() {
  int M;
  scanf("%d%d", &n, &M);
  root = 1;
  for (int i = 2; i <= n; i++) {
    scanf("%d", &m);
    G[i].push_back(m);
    G[m].push_back(i);
  }
  tot = 0;
  dfs1(root, 0, 0), dfs2(root, 0, 0);
  build(1, n);
  char op[20];
  while (M--) {
    int x, y, z;
    scanf("%s", op);
    if (op[0] == '1') {
      scanf("%d", &x);
      solve_add(x, x, 1);
    } else if (op[0] == '2') {
      scanf("%d", &x);
      update_subtree(x, -1);
      int t = solve_query(1, x).mx;
      if (t >= 0) {
        solve_add(x, x, -t - 1);
      }
    } else {
      scanf("%d", &x);
      int t = solve_query(1, x).mx;
      printf("%s\n", t >= 0 ? "black" : "white");
    }
  }
  return 0;
}
