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;
const long long int mini = -1e15;
vector<int> l[100009];
long long int tree[4 * 100009], best[4 * 100009];
int n, p[20][100009], lvl[100009], sub[100009], tin[100009], tout[100009],
    lazy[4 * 100009];
int baseArray[100009], ptr;
int chainInd[100009], posInBase[100009], chainHead[100009], chainNo;
void build(int node, int start, int end) {
  if (start == end) {
    tree[node] = best[node] = -1;
    return;
  }
  int mid = (start + end) / 2;
  build(2 * node, start, mid);
  build(2 * node + 1, mid + 1, end);
  tree[node] = tree[2 * node] + tree[2 * node + 1];
  best[node] = max(best[2 * node + 1], best[2 * node] + tree[2 * node + 1]);
  return;
}
void range_update(int node, int start, int end, int l, int r) {
  if (lazy[node]) {
    tree[node] = -1 * (end - start + 1);
    best[node] = -1;
    if (start != end) {
      lazy[2 * node] = lazy[2 * node + 1] = 1;
    }
    lazy[node] = 0;
  }
  if (start > end || start > r || end < l) {
    return;
  }
  if (start >= l && end <= r) {
    tree[node] = -1 * (end - start + 1);
    best[node] = -1;
    if (start != end) {
      lazy[2 * node] = lazy[2 * node + 1] = 1;
    }
    lazy[node] = 0;
    return;
  }
  int mid = (start + end) / 2;
  range_update(2 * node, start, mid, l, r);
  range_update(2 * node + 1, mid + 1, end, l, r);
  tree[node] = tree[2 * node] + tree[2 * node + 1];
  best[node] = max(best[2 * node + 1], best[2 * node] + tree[2 * node + 1]);
  return;
}
void point_update(int node, int start, int end, int idx, long long int val) {
  if (lazy[node]) {
    tree[node] = -1 * (end - start + 1);
    best[node] = -1;
    if (start != end) {
      lazy[2 * node] = lazy[2 * node + 1] = 1;
    }
    lazy[node] = 0;
  }
  if (start > end || start > idx || end < idx) {
    return;
  }
  if (start == end) {
    tree[node] += val;
    best[node] += val;
    return;
  }
  int mid = (start + end) / 2;
  point_update(2 * node, start, mid, idx, val);
  point_update(2 * node + 1, mid + 1, end, idx, val);
  tree[node] = tree[2 * node] + tree[2 * node + 1];
  best[node] = max(best[2 * node + 1], best[2 * node] + tree[2 * node + 1]);
  return;
}
pair<long long int, long long int> query_tree(int node, int start, int end,
                                              int l, int r) {
  if (r < start || end < l) {
    return make_pair(mini, mini);
  }
  if (lazy[node]) {
    tree[node] = -1 * (end - start + 1);
    best[node] = -1;
    if (start != end) {
      lazy[2 * node] = lazy[2 * node + 1] = 1;
    }
    lazy[node] = 0;
  }
  if (l <= start && end <= r) {
    return make_pair(best[node], tree[node]);
  }
  int mid = (start + end) / 2;
  auto p1 = query_tree(2 * node, start, mid, l, r);
  auto p2 = query_tree(2 * node + 1, mid + 1, end, l, r);
  if (p1 == make_pair(mini, mini)) {
    return p2;
  } else if (p2 == make_pair(mini, mini)) {
    return p1;
  }
  pair<long long int, long long int> final;
  final.second = p1.second + p2.second;
  final.first = max(p2.first, p1.first + p2.second);
  return final;
}
void dfs(int ver, int par) {
  int i, j, t1, t2, t3, t4;
  sub[ver] = 1;
  for (i = 0; i < (int)l[ver].size(); i++) {
    t1 = l[ver][i];
    if (t1 == par) {
      continue;
    }
    lvl[t1] = lvl[ver] + 1;
    p[0][t1] = ver;
    dfs(t1, ver);
    sub[ver] += sub[t1];
  }
  return;
}
void preprocess() {
  int i, j, t1, t2, t3, t4;
  p[0][1] = -1;
  lvl[1] = 0;
  dfs(1, -1);
}
int query_up(int u, int v) {
  int i, j, t1, t2, t3, t4, temp, uchain, vchain = chainInd[v];
  long long int buf1, buf2, buf3, buf4, tempans, sum;
  t1 = ptr;
  sum = 0;
  tempans = mini;
  while (1) {
    uchain = chainInd[u];
    if (uchain == vchain) {
      auto it = query_tree(1, 1, t1, posInBase[v], posInBase[u]);
      tempans = max(tempans, it.first + sum);
      sum += it.second;
      break;
    }
    auto it = query_tree(1, 1, t1, posInBase[chainHead[uchain]], posInBase[u]);
    tempans = max(tempans, it.first + sum);
    sum += it.second;
    u = chainHead[uchain];
    u = p[0][u];
  }
  return tempans;
}
void HLD(int ver, int par) {
  int newCost, specialChild = -1, i, j, t1, t2, t3, t4;
  if (chainHead[chainNo] == -1) {
    chainHead[chainNo] = ver;
  }
  chainInd[ver] = chainNo;
  tin[ver] = ++ptr;
  posInBase[ver] = ptr;
  baseArray[ptr] = ver;
  for (i = 0; i < (int)l[ver].size(); i++) {
    t1 = l[ver][i];
    if (t1 == par) {
      continue;
    }
    if (specialChild == -1 || sub[specialChild] < sub[t1]) {
      specialChild = t1;
    }
  }
  if (specialChild != -1) {
    HLD(specialChild, ver);
  }
  for (i = 0; i < (int)l[ver].size(); i++) {
    t1 = l[ver][i];
    if (t1 == par || t1 == specialChild) {
      continue;
    }
    chainNo++;
    HLD(t1, ver);
  }
  tout[ver] = ptr;
  return;
}
int main() {
  int i, j, t1, t2, t3, t4, q;
  long long int buf1, buf2, buf3, buf4, ans;
  scanf("%d %d", &n, &q);
  for (i = 2; i <= n; i++) {
    scanf("%d", &t1);
    l[t1].push_back(i);
    l[i].push_back(t1);
  }
  for (i = 0; i <= n; i++) {
    chainHead[i] = -1;
  }
  ptr = 0;
  chainNo = 1;
  preprocess();
  HLD(1, -1);
  build(1, 1, n);
  for (i = 0; i < q; i++) {
    scanf("%d %d", &t1, &t2);
    if (t1 == 1) {
      point_update(1, 1, n, tin[t2], 1);
    } else if (t1 == 2) {
      range_update(1, 1, n, tin[t2], tout[t2]);
      buf1 = query_up(t2, 1);
      if (buf1 >= 0) {
        point_update(1, 1, n, tin[t2], -(buf1 + 1));
      }
    } else {
      ans = query_up(t2, 1);
      if (ans >= 0) {
        printf("black\n");
      } else {
        printf("white\n");
      }
    }
  }
  return 0;
}