#include <bits/stdc++.h>
using namespace std;
const int inf32 = 1e8 + 9, MX = inf32 * 2;
const long long inf64 = 1e18 + 18;
const long long mod = 998244353;
const int N = 1e5 + 5, LG = 20;
struct Edge {
  int to;
  int ind;
};
pair<int, int> edges[N];
pair<int, int> indInPath[N];
int ans[N];
struct Path {
  struct ST {
    ST *l = nullptr, *r = nullptr;
    int sum = 0;
    void Inc(int lq, int rq, int lt, int rt) {
      if (lq > rq) return;
      if (lq == lt && rq == rt) {
        ++sum;
        return;
      }
      if (!l) {
        l = new ST;
        r = new ST;
      }
      int h = (lt + rt) >> 1;
      l->Inc(lq, min(rq, h), lt, h);
      r->Inc(max(h + 1, lq), rq, h + 1, rt);
    }
    void Fill(const vector<int> &path, int lt, int rt) {
      if (lt == rt) {
        ans[path[lt]] = sum;
        return;
      }
      if (!l) {
        l = new ST;
        r = new ST;
      }
      l->sum += sum;
      r->sum += sum;
      int h = (lt + rt) >> 1;
      l->Fill(path, lt, h);
      r->Fill(path, h + 1, rt);
    }
  };
  vector<int> path;
  unordered_map<int, int> edgeForNode;
  int lastV;
  ST *root = new ST;
  Path(const vector<int> &vc, int v) {
    path = vc;
    lastV = v;
    for (int i = 0; i < path.size(); ++i) {
      edgeForNode[edges[path[i]].second] = i;
    }
  }
  void Query(int a, int b) { root->Inc(a, b, 0, path.size() - 1); }
  void Fill() { root->Fill(path, 0, path.size() - 1); }
};
vector<Path> hld;
int par[N][LG], parEdge[N], tin[N], tout[N], sz[N], t;
vector<Edge> gr[N];
vector<int> hasNoHeavy;
bool heavy[N];
const int root = 1;
void Dfs(int cur, int pr = 0) {
  tin[cur] = t++;
  par[cur][0] = pr;
  for (int i = 1; i < LG; ++i) par[cur][i] = par[par[cur][i - 1]][i - 1];
  sz[cur] = 1;
  for (auto &edge : gr[cur]) {
    if (edge.to != pr) {
      Dfs(edge.to, cur);
      parEdge[edge.to] = edge.ind;
      sz[cur] += sz[edge.to];
    }
  }
  bool hasHeavy = false;
  for (auto &x : gr[cur]) {
    if (x.to != pr) {
      if (edges[x.ind].second == x.to)
        swap(edges[x.ind].first, edges[x.ind].second);
      if (sz[x.to] >= (sz[cur] + 1) / 2) {
        heavy[x.ind] = hasHeavy = true;
        break;
      }
    }
  }
  if (!hasHeavy) hasNoHeavy.push_back(cur);
  tout[cur] = t++;
}
bool IsPar(int a, int b) { return tin[a] <= tin[b] && tout[a] >= tout[b]; }
int Lca(int a, int b) {
  if (IsPar(a, b)) return a;
  if (IsPar(b, a)) return b;
  for (int i = LG - 1; i >= 0; --i) {
    if (par[a][i] && !IsPar(par[a][i], b)) a = par[a][i];
  }
  return par[a][0];
}
void BuildHeavyLight() {
  for (auto &x : hasNoHeavy) {
    if (x == root) continue;
    vector<int> path;
    int cur = x;
    while (cur != root) {
      for (auto &edge : gr[cur]) {
        if (par[cur][0] == edge.to) {
          indInPath[edge.ind] = {hld.size(), path.size()};
          path.push_back(edge.ind);
          cur = edge.to;
          break;
        }
      }
      if (!heavy[path.back()]) break;
    }
    hld.push_back(Path(path, cur));
  }
}
void IncPath(int a, int b) {
  while (a != b) {
    int pathInd = indInPath[parEdge[a]].first;
    int inPath = indInPath[parEdge[a]].second;
    if (IsPar(b, hld[pathInd].lastV)) {
      hld[pathInd].Query(inPath, hld[pathInd].path.size() - 1);
      a = hld[pathInd].lastV;
    } else {
      hld[pathInd].Query(inPath, hld[pathInd].edgeForNode[b]);
      return;
    }
  }
}
void Solve() {
  int n, q, a, b;
  scanf("%d", &n);
  for (int i = 0; i < n - 1; ++i) {
    scanf("%d%d", &a, &b);
    gr[a].push_back(Edge{b, i});
    gr[b].push_back(Edge{a, i});
    edges[i] = {a, b};
  }
  Dfs(root);
  BuildHeavyLight();
  scanf("%d", &q);
  while (q--) {
    scanf("%d%d", &a, &b);
    int lca = Lca(a, b);
    IncPath(a, lca);
    IncPath(b, lca);
  }
  for (auto &x : hld) x.Fill();
  for (int i = 0; i < n - 1; ++i) printf("%d ", ans[i]);
}
int main() {
  Solve();
  return 0;
}
