#include <bits/stdc++.h>
using namespace std;
void printVector(vector<int> a) {
  for (int ii = 0; ii < a.size(); ii++) cout << a[ii] << endl;
}
class SegmentTree {
 private:
  vector<int> fill, empty;
  int n;
  int left(int p) { return p << 1; }
  int right(int p) { return (p << 1) + 1; }
  void propagate(int p, int L, int R) {
    if (fill[p] > -1) {
      int p1 = left(p);
      int p2 = right(p);
      fill[p1] = max(fill[p1], fill[p]);
      fill[p2] = max(fill[p2], fill[p]);
      fill[p] = -1;
    }
  }
  int maxfillquery(int p, int L, int R, int i) {
    if (i > R || i < L) return -1;
    if (L == i && R == i) return fill[p];
    propagate(p, L, R);
    int p1 = maxfillquery(left(p), L, (L + R) / 2, i);
    int p2 = maxfillquery(right(p), (L + R) / 2 + 1, R, i);
    return max(p1, p2);
  }
  int maxemptyquery(int p, int L, int R, int i, int j) {
    if (i > R || j < L) return -1;
    if (L >= i && R <= j) return empty[p];
    int p1 = maxemptyquery(left(p), L, (L + R) / 2, i, j);
    int p2 = maxemptyquery(right(p), (L + R) / 2 + 1, R, i, j);
    return max(p1, p2);
  }
  int update_point(int p, int L, int R, int idx, int new_value) {
    int i = idx, j = idx;
    if (i > R || j < L) return empty[p];
    if (L == i && R == j) {
      return empty[p] = new_value;
    }
    int p1, p2;
    p1 = update_point(left(p), L, (L + R) / 2, idx, new_value);
    p2 = update_point(right(p), (L + R) / 2 + 1, R, idx, new_value);
    return empty[p] = max(p1, p2);
  }
  int update_range(int p, int L, int R, int i, int j, int new_value) {
    if (i > R || j < L) return fill[p];
    if (i <= L && R <= j) {
      return fill[p] = new_value;
    }
    propagate(p, L, R);
    int p1, p2;
    p1 = update_range(left(p), L, (L + R) / 2, i, j, new_value);
    p2 = update_range(right(p), (L + R) / 2 + 1, R, i, j, new_value);
  }

 public:
  SegmentTree(int a, int b = 0) {
    n = a;
    fill.assign(4 * n, b);
    empty.assign(4 * n, b);
  }
  int maxfillquery(int i) { return maxfillquery(1, 0, n - 1, i); }
  int maxemptyquery(int i, int j) { return maxemptyquery(1, 0, n - 1, i, j); }
  int update_point(int idx, int new_value) {
    return update_point(1, 0, n - 1, idx, new_value);
  }
  int update_range(int i, int j, int new_value) {
    return update_range(1, 0, n - 1, i, j, new_value);
  }
};
int timeCount = 0;
struct entry {
  int start;
  int end;
  entry() {}
  entry(int a, int b) {
    start = a;
    end = b;
  }
} visitTime[500100];
vector<vector<int> > adjList;
void dfs(int u, int par) {
  visitTime[u].start = timeCount++;
  for (auto v : adjList[u])
    if (v != par) {
      dfs(v, u);
    }
  visitTime[u].end = timeCount++;
}
int main() {
  int n;
  cin >> n;
  adjList.assign(n + 10, vector<int>());
  int u, v;
  for (int i = 1; i <= n - 1; i++) {
    scanf("%d %d", &u, &v);
    adjList[u].push_back(v);
    adjList[v].push_back(u);
  }
  dfs(1, 0);
  SegmentTree A(timeCount, -1);
  int q;
  cin >> q;
  for (int i = 1; i <= q; i++) {
    scanf("%d %d", &u, &v);
    if (u == 1) {
      A.update_range(visitTime[v].start, visitTime[v].end, i);
    } else if (u == 2) {
      A.update_point(visitTime[v].start, i);
    } else {
      int x = A.maxemptyquery(visitTime[v].start, visitTime[v].end);
      int y = A.maxfillquery(visitTime[v].start);
      printf("%d\n", (x > y || y == -1) ? 0 : 1);
    }
  }
  return 0;
}
