Problem: 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>

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
namespace whatever {
struct information_type {
  int suffix, sum;
  int reference_suffix, reference_sum;
};
void combine(const information_type &a, const information_type &b,
             information_type &result) {
  int result_suffix = max(a.suffix + b.sum, b.suffix);
  result.sum = a.sum + b.sum;
  result.suffix = result_suffix;
}
struct tag_type {
  unsigned char cleared;
};
void apply(const tag_type &a, information_type &b) {
  if (a.cleared) {
    b.suffix = b.reference_suffix;
    b.sum = b.reference_sum;
  }
}
void apply(const tag_type &a, tag_type &b) { b.cleared |= a.cleared; }
void clear(tag_type &a) { a.cleared = 0; }
struct node_type {
  information_type information;
  tag_type tag;
};
node_type tree[1 << 18];
int s, l;
void push_down(int cur) {
  assert(cur > 0);
  apply(tree[cur].tag, tree[cur].information);
  if (cur < s) {
    apply(tree[cur].tag, tree[cur * 2].tag);
    apply(tree[cur].tag, tree[cur * 2 + 1].tag);
  }
  clear(tree[cur].tag);
}
void path_push_down(int cur) {
  assert(cur >= s);
  for (int i = l; i != -1; --i) push_down(cur >> i);
}
void push_up(int cur) {
  assert(cur < s);
  push_down(cur * 2);
  push_down(cur * 2 + 1);
  combine(tree[cur * 2].information, tree[cur * 2 + 1].information,
          tree[cur].information);
}
void path_push_up(int cur) {
  cur >>= 1;
  while (cur) {
    push_up(cur);
    cur >>= 1;
  }
}
void init_tree(int n) {
  s = n;
  while (s & (s - 1)) s += (s & -s);
  while ((1 << l) != s) ++l;
  for (int i = 0; i < s; ++i) {
    clear(tree[s + i].tag);
    tree[s + i].information.suffix = tree[s + i].information.sum = -1;
  }
  for (int i = s - 1; i > 0; --i) {
    clear(tree[i].tag);
    push_up(i);
  }
  for (int i = s * 2 - 1; i > 0; --i) {
    tree[i].information.reference_suffix = tree[i].information.suffix;
    tree[i].information.reference_sum = tree[i].information.sum;
  }
}
information_type point_query(int first) {
  first += s;
  path_push_down(first);
  return tree[first].information;
}
information_type range_query(int first, int last) {
  first += s;
  last += s;
  if (first == last) {
    path_push_down(first);
    return tree[first].information;
  }
  path_push_down(first);
  path_push_down(last);
  information_type left_information = tree[first].information;
  information_type right_information = tree[last].information;
  while ((first ^ last) != 1) {
    if (!(first & 1)) {
      push_down(first + 1);
      combine(left_information, tree[first + 1].information, left_information);
    }
    if (last & 1) {
      push_down(last - 1);
      combine(tree[last - 1].information, right_information, right_information);
    }
    first >>= 1;
    last >>= 1;
  }
  combine(left_information, right_information, left_information);
  return left_information;
}
void point_apply(int first, const tag_type &tag) {
  first += s;
  path_push_down(first);
  apply(tag, tree[first].tag);
  path_push_up(first);
}
void range_apply(int first, int last, const tag_type &tag) {
  first += s;
  last += s;
  if (first == last) {
    path_push_down(first);
    apply(tag, tree[first].tag);
    path_push_up(first);
    return;
  }
  path_push_down(first);
  path_push_down(last);
  apply(tag, tree[first].tag);
  apply(tag, tree[last].tag);
  while ((first ^ last) != 1) {
    if (!(first & 1)) apply(tag, tree[first + 1].tag);
    if (last & 1) apply(tag, tree[last - 1].tag);
    first >>= 1;
    last >>= 1;
    push_up(first);
    push_up(last);
  }
  path_push_up(first);
}
vector<int> adj[100001];
int size[100001];
int heavy[100001];
int father[100001];
void dfs1(int cur) {
  size[cur] = 1;
  for (size_t i = 0; i < adj[cur].size(); ++i) {
    int to = adj[cur][i];
    father[to] = cur;
    dfs1(to);
    size[cur] += size[to];
    if (size[heavy[cur]] < size[to]) heavy[cur] = to;
  }
}
int top[100001];
int dfn[100001];
int last[100001];
int dfs_time = -1;
void dfs2(int cur) {
  dfn[cur] = ++dfs_time;
  if (heavy[cur]) {
    top[heavy[cur]] = top[cur];
    dfs2(heavy[cur]);
  }
  for (size_t i = 0; i < adj[cur].size(); ++i) {
    int to = adj[cur][i];
    if (to == heavy[cur]) continue;
    top[to] = to;
    dfs2(to);
  }
  last[cur] = dfs_time;
}
int readu() {
  char ch = getchar();
  while (!isdigit(ch)) ch = getchar();
  int value = ch - '0';
  ch = getchar();
  while (isdigit(ch)) {
    value = value * 10 + ch - '0';
    ch = getchar();
  }
  return value;
}
information_type path_query(int cur) {
  information_type result;
  result.suffix = -2000000000;
  result.sum = 0;
  while (cur) {
    combine(range_query(dfn[top[cur]], dfn[cur]), result, result);
    cur = father[top[cur]];
  }
  return result;
}
void run() {
  int n = readu();
  int q = readu();
  for (int i = 2; i <= n; ++i) adj[readu()].push_back(i);
  dfs1(1);
  top[1] = 1;
  dfs2(1);
  init_tree(n);
  while (--q != -1) {
    int t = readu();
    int v = readu();
    if (t == 1) {
      int first = dfn[v] + s;
      path_push_down(first);
      ++tree[first].information.suffix;
      ++tree[first].information.sum;
      path_push_up(first);
    } else if (t == 2) {
      range_apply(dfn[v], last[v], (tag_type){1});
      information_type result = path_query(v);
      if (result.suffix != -1) {
        int first = dfn[v] + s;
        path_push_down(first);
        tree[first].information.suffix += -result.suffix - 1;
        tree[first].information.sum += -result.suffix - 1;
        path_push_up(first);
      }
    } else if (t == 3) {
      information_type result = path_query(v);
      puts(result.suffix < 0 ? "white" : "black");
    } else
      assert(0);
  }
}
}  // namespace whatever
int main() { whatever::run(); }