#include <bits/stdc++.h>
using namespace std;
struct SCC {
  int V;
  vector<vector<int>> adj;
  vector<int> discovery, low_link;
  int index;
  int S;
  vector<int> stack;
  vector<bool> on_stack;
  vector<vector<int>> components;
  vector<int> which_component;
  SCC(int v = 0) {
    if (v > 0) init(v);
  }
  SCC(const vector<vector<int>> &_adj) { init(_adj); }
  void init(int v) {
    V = v;
    adj.assign(V, vector<int>());
  }
  void init(const vector<vector<int>> &_adj) {
    adj = _adj;
    V = adj.size();
  }
  void add_edge(int a, int b) { adj[a].push_back(b); }
  void dfs(int node) {
    discovery[node] = low_link[node] = index++;
    stack[S++] = node;
    on_stack[node] = true;
    for (int neighbor : adj[node])
      if (discovery[neighbor] == -1) {
        dfs(neighbor);
        low_link[node] = min(low_link[node], low_link[neighbor]);
      } else if (on_stack[neighbor]) {
        low_link[node] = min(low_link[node], discovery[neighbor]);
      }
    if (low_link[node] == discovery[node]) {
      components.emplace_back();
      vector<int> &component = components.back();
      int x;
      do {
        assert(S > 0);
        x = stack[--S];
        on_stack[x] = false;
        component.push_back(x);
        which_component[x] = components.size() - 1;
      } while (x != node);
    }
  }
  void build() {
    discovery.assign(V, -1);
    low_link.assign(V, -1);
    which_component.assign(V, -1);
    S = 0;
    stack.resize(V);
    on_stack.assign(V, false);
    index = 0;
    components.clear();
    for (int i = 0; i < V; i++)
      if (discovery[i] == -1) dfs(i);
  }
};
struct two_sat {
  int n;
  vector<vector<int>> adj;
  vector<bool> assignment;
  two_sat(int _n = 0) { init(_n); }
  void init(int _n) {
    n = _n;
    adj.assign(2 * n, vector<int>());
  }
  int flip(int index) { return index ^ 1; }
  int new_var() {
    adj.emplace_back();
    adj.emplace_back();
    n++;
    return 2 * n - 2;
  }
  void implies(int a, int b) {
    adj[a].push_back(b);
    adj[flip(b)].push_back(flip(a));
  }
  void either(int a, int b) {
    adj[flip(a)].push_back(b);
    adj[flip(b)].push_back(a);
  }
  void set_value(int a) { adj[flip(a)].push_back(a); }
  void at_most_one(const vector<int> &vars) {
    int s = vars.size();
    if (s < 8) {
      for (int i = 0; i < s; i++)
        for (int j = i + 1; j < s; j++) either(flip(vars[i]), flip(vars[j]));
      return;
    }
    int aux = -1;
    for (int i = 0; i < s - 1; i++) {
      int prev_aux = aux;
      aux = new_var();
      implies(vars[i], aux);
      if (i > 0) {
        implies(prev_aux, aux);
        implies(prev_aux, flip(vars[i]));
      }
    }
    implies(aux, flip(vars[s - 1]));
  }
  bool solve() {
    SCC scc(adj);
    scc.build();
    for (int i = 0; i < n; i++)
      if (scc.which_component[2 * i] == scc.which_component[2 * i + 1])
        return false;
    assignment.resize(n);
    vector<bool> done(n, false);
    for (vector<int> &component : scc.components)
      for (int x : component)
        if (!done[x / 2]) {
          done[x / 2] = true;
          assignment[x / 2] = x % 2 == 0;
        }
    return true;
  }
};
two_sat TS;
struct seg_tree {
  int tree_n;
  vector<vector<int>> tree;
  seg_tree(int n = 0) {
    tree_n = 0;
    if (n > 0) init(n);
  }
  void init(int n) {
    tree_n = 1;
    while (tree_n < n) tree_n *= 2;
    tree.assign(2 * tree_n, vector<int>());
  }
  bool empty() const { return tree_n == 0; }
  void process_range(int position, int start, int end, int a, int b,
                     int var_index) {
    if (a <= start && end <= b) {
      tree[position].push_back(var_index);
      return;
    }
    if (position >= tree_n) return;
    int mid = (start + end) / 2;
    if (a < mid) process_range(2 * position, start, mid, a, b, var_index);
    if (b > mid) process_range(2 * position + 1, mid, end, a, b, var_index);
  }
  void add_path(int a, int b, int var_index) {
    process_range(1, 0, tree_n, a, b, var_index);
  }
  void build_implications(int position = 1, int parent_var = -1) {
    TS.at_most_one(tree[position]);
    if (parent_var != -1) {
      for (int var : tree[position]) TS.implies(parent_var, TS.flip(var));
    }
    if (position >= tree_n) return;
    int my_var = TS.new_var();
    if (parent_var != -1) TS.implies(parent_var, my_var);
    for (int var : tree[position]) TS.implies(var, my_var);
    build_implications(2 * position, my_var);
    build_implications(2 * position + 1, my_var);
  }
};
struct heavy_light {
  int n;
  bool vertex_mode;
  vector<vector<int>> adj;
  vector<int> parent;
  vector<int> depth;
  vector<int> subtree_size;
  vector<int> chain_root;
  vector<int> chain_size;
  vector<seg_tree> chain_tree;
  heavy_light(int _n = 0, bool _vertex_mode = false) {
    if (_n > 0) init(_n, _vertex_mode);
  }
  void init(int _n, bool _vertex_mode) {
    n = _n;
    vertex_mode = _vertex_mode;
    adj.clear();
    adj.resize(n);
    parent.resize(n);
    depth.resize(n);
    subtree_size.resize(n);
    chain_root.resize(n);
    chain_size.assign(n, 0);
    chain_tree.clear();
    chain_tree.resize(n);
  }
  void add_edge(int a, int b) {
    adj[a].push_back(b);
    adj[b].push_back(a);
  }
  void dfs(int node, int par) {
    parent[node] = par;
    depth[node] = par == -1 ? 0 : depth[par] + 1;
    subtree_size[node] = 1;
    for (int neighbor : adj[node])
      if (neighbor != par) {
        dfs(neighbor, node);
        subtree_size[node] += subtree_size[neighbor];
      }
  }
  void chain_dfs(int node, bool heavy) {
    chain_root[node] = heavy ? chain_root[parent[node]] : node;
    chain_size[chain_root[node]]++;
    int biggest_subtree = 0;
    int heavy_child = -1;
    for (int neighbor : adj[node])
      if (neighbor != parent[node] &&
          subtree_size[neighbor] > biggest_subtree) {
        biggest_subtree = subtree_size[neighbor];
        heavy_child = neighbor;
      }
    for (int neighbor : adj[node])
      if (neighbor != parent[node])
        chain_dfs(neighbor, neighbor == heavy_child);
  }
  void build() {
    dfs(0, -1);
    chain_dfs(0, false);
    for (int i = 0; i < n; i++)
      if (chain_root[i] == i) chain_tree[i].init(chain_size[i]);
  }
  template <typename T_tree_op>
  void process_path(int u, int v, T_tree_op &&op) {
    while (chain_root[u] != chain_root[v]) {
      if (depth[chain_root[u]] > depth[chain_root[v]]) swap(u, v);
      int root = chain_root[v];
      op(chain_tree[root], 0, depth[v] - depth[root] + 1);
      v = parent[chain_root[v]];
    }
    if (depth[u] > depth[v]) swap(u, v);
    int root = chain_root[v];
    op(chain_tree[root], depth[u] - depth[root] + (vertex_mode ? 0 : 1),
       depth[v] - depth[root] + 1);
  }
  void add_path(int u, int v, int var_index) {
    process_path(u, v, [&](seg_tree &tree, int a, int b) {
      tree.add_path(a, b, var_index);
    });
  }
  void build_all_trees() {
    for (seg_tree &tree : chain_tree)
      if (!tree.empty()) tree.build_implications();
  }
};
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int N;
  cin >> N;
  heavy_light HLD(N);
  for (int i = 0; i < N - 1; i++) {
    int u, v;
    cin >> u >> v;
    u--;
    v--;
    HLD.add_edge(u, v);
  }
  HLD.build();
  int M;
  cin >> M;
  vector<int> vars(M);
  for (int i = 0; i < M; i++) vars[i] = TS.new_var();
  for (int i = 0; i < M; i++) {
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    a--;
    b--;
    c--;
    d--;
    HLD.add_path(a, b, vars[i]);
    HLD.add_path(c, d, TS.flip(vars[i]));
  }
  HLD.build_all_trees();
  if (!TS.solve()) {
    cout << "NO" << '\n';
    return 0;
  }
  cout << "YES" << '\n';
  for (int i = 0; i < M; i++) cout << (TS.assignment[i] ? 1 : 2) << '\n';
}
