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 IO {
char ss[1 << 24], *A = ss, *B = ss;
inline char gc() {
  return A == B && (B = (A = ss) + fread(ss, 1, 1 << 24, stdin), A == B) ? EOF
                                                                         : *A++;
}
template <class T>
void read(T &x) {
  register int f = 1, c;
  while (c = gc(), c < 48 || c > 57)
    if (c == '-') f = -1;
  x = (c ^ 48);
  while (c = gc(), c > 47 && c < 58) x = (x << 3) + (x << 1) + (c ^ 48);
  x *= f;
}
char sr[1 << 24], z[20];
long long Z, C1 = -1;
template <class T>
void wer(T x) {
  if (x < 0) sr[++C1] = '-', x = -x;
  while (z[++Z] = x % 10 + 48, x /= 10)
    ;
  while (sr[++C1] = z[Z], --Z)
    ;
}
inline void wer1() { sr[++C1] = ' '; }
inline void wer2() { sr[++C1] = '\n'; }
template <class T>
inline void maxa(T &x, T y) {
  if (x < y) x = y;
}
template <class T>
inline void mina(T &x, T y) {
  if (x > y) x = y;
}
template <class T>
inline T MAX(T x, T y) {
  return x > y ? x : y;
}
template <class T>
inline T MIN(T x, T y) {
  return x < y ? x : y;
}
};  // namespace IO
using namespace IO;
const int N = 2.1e5;
struct re {
  int a, b;
} e[N * 2];
int head[N], l, n, m;
inline void arr(int x, int y) {
  e[++l].a = head[x];
  e[l].b = y;
  head[x] = l;
}
struct re2 {
  int a[2];
  re2() { a[0] = a[1] = 0; }
  re2(int x, int y) {
    a[0] = x;
    a[1] = y;
  };
  re2 operator*(const re2 &o) const {
    re2 c;
    c.a[0] = a[0] + o.a[0];
    c.a[1] = MAX(a[1] + o.a[0], o.a[1]);
    return c;
  }
};
int fa[N], num[N], son[N], dfn[N], top[N], cnt;
void dfs(int x, int y) {
  num[x] = 1;
  fa[x] = y;
  for (register int u = head[x]; u; u = e[u].a) {
    int v = e[u].b;
    if (v != y) {
      dfs(v, x);
      num[x] += num[v];
      if (num[son[x]] < num[v]) son[x] = v;
    }
  }
}
void dfs1(int x, int y, int z) {
  top[x] = y;
  dfn[x] = ++cnt;
  if (son[x]) dfs1(son[x], y, x);
  for (register int u = head[x]; u; u = e[u].a) {
    int v = e[u].b;
    if (v != z && v != son[x]) {
      dfs1(v, v, x);
    }
  }
}
struct sgt {
  re2 sum[N * 4];
  bool lazy[N * 4];
  inline void down(int x, int h, int t) {
    if (lazy[x]) {
      lazy[x * 2] = lazy[x * 2 + 1] = 1;
      lazy[x] = 0;
      sum[x * 2] = re2(-(((h + t) >> 1) - h + 1), -1);
      sum[x * 2 + 1] = re2(-(t - ((h + t) >> 1)), -1);
    }
  }
  void build(int x, int h, int t) {
    if (h == t) {
      sum[x] = re2(-1, -1);
      return;
    }
    build(x * 2, h, ((h + t) >> 1));
    build(x * 2 + 1, ((h + t) >> 1) + 1, t);
    sum[x] = sum[x * 2] * sum[x * 2 + 1];
  }
  void change(int x, int h, int t, int pos, int k) {
    if (h == t) {
      sum[x] = re2(k, k);
      return;
    }
    down(x, h, t);
    if (pos <= ((h + t) >> 1))
      change(x * 2, h, ((h + t) >> 1), pos, k);
    else
      change(x * 2 + 1, ((h + t) >> 1) + 1, t, pos, k);
    sum[x] = sum[x * 2] * sum[x * 2 + 1];
  }
  re2 query(int x, int h, int t, int h1, int t1) {
    if (h1 <= h && t <= t1) return sum[x];
    down(x, h, t);
    if (h1 <= ((h + t) >> 1) && ((h + t) >> 1) < t1)
      return query(x * 2, h, ((h + t) >> 1), h1, t1) *
             query(x * 2 + 1, ((h + t) >> 1) + 1, t, h1, t1);
    else if (h1 <= ((h + t) >> 1))
      return query(x * 2, h, ((h + t) >> 1), h1, t1);
    else
      return query(x * 2 + 1, ((h + t) >> 1) + 1, t, h1, t1);
  }
  void push(int x, int h, int t, int h1, int t1) {
    if (h1 <= h && t <= t1) {
      lazy[x] = 1;
      sum[x] = re2(-(t - h + 1), -1);
      return;
    }
    down(x, h, t);
    if (h1 <= ((h + t) >> 1)) push(x * 2, h, ((h + t) >> 1), h1, t1);
    if (((h + t) >> 1) < t1) push(x * 2 + 1, ((h + t) >> 1) + 1, t, h1, t1);
    sum[x] = sum[x * 2] * sum[x * 2 + 1];
  }
} S;
inline int query(int x) {
  int ans = -1;
  re2 p1 = re2(0, -1);
  while (x) {
    re2 p = S.query(1, 1, n, dfn[top[x]], dfn[x]);
    p1 = p * p1;
    ans = max(ans, p1.a[1]);
    x = fa[top[x]];
  }
  return ans;
}
int main() {
  read(n);
  read(m);
  for (int i = 2; i <= n; i++) {
    int x;
    read(x);
    arr(i, x);
    arr(x, i);
  }
  dfs(1, 0);
  dfs1(1, 1, 0);
  S.build(1, 1, n);
  for (int i = 1; i <= m; i++) {
    int kk, x;
    read(kk);
    read(x);
    if (kk == 1) {
      S.change(1, 1, n, dfn[x], S.query(1, 1, n, dfn[x], dfn[x]).a[0] + 1);
    }
    if (kk == 2) {
      S.push(1, 1, n, dfn[x], dfn[x] + num[x] - 1);
      int ans = query(x);
      S.change(1, 1, n, dfn[x], -ans - 2);
    }
    if (kk == 3) {
      if (query(x) >= 0)
        cout << "black" << endl;
      else
        cout << "white" << endl;
    }
  }
  return 0;
}