#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <map>
using namespace std;

struct query
{
	int l = 0, r = 0, k = 0;
};

struct segm
{
	int l = 0, r = 0, sum = 0, push = -1;
};

vector<segm> t, a;

void build(int v, int tl, int tr)
{
	if (tl == tr)
		t[v] = a[tl];
	else
	{
		int tm = (tl + tr) / 2;
		build(v * 2, tl, tm);
		build(v * 2 + 1, tm + 1, tr);
		t[v].l = t[v * 2].l;
		t[v].r = t[v * 2 + 1].r;
	}
}

void push(int v)
{
	if (t[v].push == -1)
		return;
	t[v * 2].push = t[v].push;
	t[v * 2 + 1].push = t[v].push;
	t[v * 2].sum = t[v].push * (t[v * 2].r - t[v * 2].l + 1);
	t[v * 2 + 1].sum = t[v].push * (t[v * 2 + 1].r - t[v * 2 + 1].l + 1);
	t[v].push = -1;
}

void upd(int v, int ttl, int ttr, int l, int r, int x)
{
	int tl = a[ttl].l, tr = a[ttr].r;
	if (l > r || tl > tr || tl > r || l > tr)
		return;
	//cout << ttl << " " << ttr << ": " << t[v].sum << endl;
	if (l <= tl && tr <= r)
	{
		t[v].sum = x * (tr - tl + 1);
		t[v].push = x;
		return;
	}
	push(v);
	int tm = (ttl + ttr) / 2;
	upd(v * 2, ttl, tm, l, r, x);
	upd(v * 2 + 1, tm + 1, ttr, l, r, x);
	t[v].sum = t[v * 2].sum + t[v * 2 + 1].sum;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, m; cin >> n >> m;
	vector<query> q(m);
	set<int> s;
	map<int, pair<bool, bool>> mp;
	for (int i = 0; i < m; i++)
	{
		cin >> q[i].l >> q[i].r >> q[i].k;
		q[i].l--; q[i].r--;
		s.insert(q[i].l);
		s.insert(q[i].r);
		mp[q[i].l].first = true;
		mp[q[i].r].second = true;
	}
	int last = -1;
	for (auto p : s)
	{
		if (last == -1)
		{
			last = p;
			continue;
		}
		if (mp[p].first * mp[p].second)
		{
			if (p - last > 0)
				a.push_back({ last, p - 1 });
			a.push_back({ p, p });
		}
		else
			a.push_back({ last, p });
		last = p + 1;
	}
	//for (auto i : a)
		//cout << i.l + 1 << " " << i.r + 1 << endl;
	int all = n;
	n = a.size();
	t.resize(n * 8);
	build(1, 0, n - 1);
	for (int i = 0; i < m; i++)
	{
		upd(1, 0, n - 1, q[i].l, q[i].r, q[i].k & 1);
		cout << all - t[1].sum << "\n";
	}
}


#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <unordered_map>
using namespace std;

struct node
{
	int l, r, sum, push;
	node(int l = 0, int r = 0, int sum = 0, int push = -1) : l(l), r(r), sum(sum), push(push) {}
	friend node operator+(node& a, node& b)
	{
		return node(a.l, b.r, a.sum + b.sum);
	}

	int get()
	{
		return r - l + 1;
	}
};

struct query
{
	int l = 0, r = 0, k = 0;
};

vector<node> a, t;

void build(int v, int tl, int tr)
{
	if (tl == tr)
		t[v] = a[tl];
	else
	{
		int tm = (tl + tr) >> 1;
		build(v * 2, tl, tm);
		build(v * 2 + 1, tm + 1, tr);
		t[v] = t[v * 2] + t[v * 2 + 1];
	}
}

void push(int v)
{
	if (t[v].push == -1)
		return;
	if (v * 2 < t.size())
	{
		t[v * 2].push = t[v].push;
		t[v * 2].sum = t[v * 2].get() * t[v].push;
	}
	if (v * 2 + 1 < t.size())
	{
		t[v * 2 + 1].push = t[v].push;
		t[v * 2 + 1].sum = t[v * 2 + 1].get() * t[v].push;
	}
	t[v].sum = t[v].get() * t[v].push;
	t[v].push = -1;
}

void update(int v, int tl, int tr, int l, int r, int x)
{
	if (tl > tr || l > r || l > tr || tl > r)
		return;
	if (l <= tl && tr <= r)
	{
		t[v].push = x;
		push(v);
		return;
	}
	push(v);
	int tm = (tl + tr) >> 1;
	update(v * 2, tl, tm, l, r, x);
	update(v * 2 + 1, tm + 1, tr, l, r, x);
	t[v] = t[v * 2] + t[v * 2 + 1];
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, q; cin >> n >> q;
	map<int, pair<bool, bool>> m;
	vector<query> s(q);
	for (int i = 0; i < q; i++)
	{
		cin >> s[i].l >> s[i].r >> s[i].k;
		m[s[i].l].first = true;
		m[s[i].r].second = true;
	}
	int last = -1;
	unordered_map<int, int> left, right;
	for (auto i : m)
	{
		if (last == -1)
		{
			last = i.first;
			if (i.second.second && i.second.first)
			{
				a.push_back(node(last, last));
				left[last] = right[last] = 0;
				last++;
			}
			continue;
		}
		if (i.second.first && i.second.second)
		{
			if (last < i.first)
			{
				a.push_back(node(last, i.first - 1));
				left[last] = right[i.first -1] = a.size() - 1;
			}
			a.push_back(node(i.first, i.first));
			left[i.first] = right[i.first] = a.size() - 1;
			last = i.first + 1;
		}
		else if (i.second.second)
		{
			a.push_back(node(last, i.first));
			left[last] = right[i.first] = a.size() - 1;
			last = -1;
		}
		else
		{
			a.push_back(node(last, i.first - 1));
			left[last] = right[i.first - 1] = a.size() - 1;
			last = i.first;
		}
	}
	t.resize(a.size() * 4);
	build(1, 0, a.size() - 1);
	for (int i = 0; i < q; i++)
	{
		int l = left[s[i].l], r = right[s[i].r];
		update(1, 0, a.size() - 1, l, r, s[i].k == 1 ? 1 : 0);
		cout << n - t[1].sum << "\n";
	}
}


#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct Node
{
	Node *l, *r;
	int sum, push;
	Node() : l(0), r(0), sum(0), push(-1) {}
};

typedef Node *node;

inline void push(node& v, int tl, int tr)
{
	if (tl == tr)
		return;
	node &l = v->l, &r = v->r;
	if (!l)
		l = new Node;
	if (!r)
		r = new Node;
	if (v->push == -1)
		return;
	l->push = v->push;
	r->push = v->push;
	int tm = (tl + tr) / 2;
	l->sum = v->push * (tm - tl + 1);
	r->sum = v->push * (tr - tm);
	v->push = -1;
}

inline void set(node& v, int tl, int tr, int l, int r, int x)
{
	if (l > r || tl > tr || tl > r || l > tr)
		return;
	push(v, tl, tr);
	if (l <= tl && tr <= r)
	{
		v->sum = x * (tr - tl + 1);
		v->push = x;
		push(v, tl, tr);
		return;
	}
	int tm = (tl + tr) / 2;
	set(v->l, tl, tm, l, r, x);
	set(v->r, tm + 1, tr, l, r, x);
	v->sum = v->l->sum + v->r->sum;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, m; cin >> n >> m;
	node v = new Node;
	for (int i = 0; i < m; i++)
	{
		int k, l, r;
		cin >> l >> r >> k;
		set(v, 0, n - 1, l - 1, r - 1, k % 2);
		cout << n - v->sum << "\n";
	}
	//system("pause");
}


#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

struct Node
{
	Node *l, *r;
	int sum, push;
	Node(Node *l = 0, Node *r = 0) : l(l), r(r), sum(0), push(-1) {}
};

typedef Node *node;

void push(node& v, int tl, int tr)
{
	if (tl == tr)
		return;
	node &l = v->l, &r = v->r;
	if (!l)
		l = new Node;
	if (!r)
		r = new Node;
	if (v->push == -1)
		return;
	l->push = v->push;
	r->push = v->push;
	int tm = (tl + tr) / 2;
	l->sum = v->push * (tm - tl + 1);
	r->sum = v->push * (tr - tm);
	v->push = -1;
}

void set(node& v, int tl, int tr, int l, int r, int x)
{
	if (l > r || tl > tr || tl > r || l > tr)
		return;
	push(v, tl, tr);
	if (l <= tl && tr <= r)
	{
		v->sum = x * (tr - tl + 1);
		v->push = x;
		push(v, tl, tr);
		return;
	}
	int tm = (tl + tr) / 2;
	set(v->l, tl, tm, l, r, x);
	set(v->r, tm + 1, tr, l, r, x);
	v->sum = v->l->sum + v->r->sum;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, m; cin >> n >> m;
	node v = new Node;
	for (int i = 0; i < m; i++)
	{
		int k, l, r; cin >> l >> r >> k;
		set(v, 0, n - 1, l - 1, r - 1, k % 2);
		cout << n - v->sum << "\n";
	}
}


#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <unordered_map>
using namespace std;

struct node
{
	int l, r, sum, push;
	node(int l = 0, int r = 0, int sum = 0, int push = -1) : l(l), r(r), sum(sum), push(push) {}
	friend node operator+(node& a, node& b)
	{
		return node(a.l, b.r, a.sum + b.sum);
	}

	int get()
	{
		return r - l + 1;
	}
};

struct query
{
	int l = 0, r = 0, k = 0;
};

vector<node> a, t;

void build(int v, int tl, int tr)
{
	if (tl == tr)
		t[v] = a[tl];
	else
	{
		int tm = (tl + tr) >> 1;
		build(v * 2, tl, tm);
		build(v * 2 + 1, tm + 1, tr);
		t[v] = t[v * 2] + t[v * 2 + 1];
	}
}

void push(int v)
{
	if (t[v].push == -1)
		return;
	if (v * 2 < t.size())
	{
		t[v * 2].push = t[v].push;
		t[v * 2].sum = t[v * 2].get() * t[v].push;
	}
	if (v * 2 + 1 < t.size())
	{
		t[v * 2 + 1].push = t[v].push;
		t[v * 2 + 1].sum = t[v * 2 + 1].get() * t[v].push;
	}
	t[v].sum = t[v].get() * t[v].push;
	t[v].push = -1;
}

void update(int v, int tl, int tr, int l, int r, int x)
{
	if (tl > tr || l > r || l > tr || tl > r)
		return;
	if (l <= tl && tr <= r)
	{
		t[v].push = x;
		push(v);
		return;
	}
	push(v);
	int tm = (tl + tr) >> 1;
	update(v * 2, tl, tm, l, r, x);
	update(v * 2 + 1, tm + 1, tr, l, r, x);
	t[v] = t[v * 2] + t[v * 2 + 1];
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, q; cin >> n >> q;
	map<int, pair<bool, bool>> m;
	vector<query> s(q);
	for (int i = 0; i < q; i++)
	{
		cin >> s[i].l >> s[i].r >> s[i].k;
		m[s[i].l].first = true;
		m[s[i].r].second = true;
	}
	int last = -1;
	unordered_map<int, int> left, right;
	for (auto i : m)
	{
		if (last == -1)
		{
			last = i.first;
			if (i.second.second && i.second.first)
			{
				a.push_back(node(last, last));
				left[last] = right[last] = 0;
				last++;
			}
			continue;
		}
		if (i.second.first && i.second.second)
		{
			if (last < i.first)
			{
				a.push_back(node(last, i.first - 1));
				left[last] = right[i.first -1] = a.size() - 1;
			}
			a.push_back(node(i.first, i.first));
			left[i.first] = right[i.first] = a.size() - 1;
			last = i.first + 1;
		}
		else if (i.second.second)
		{
			a.push_back(node(last, i.first));
			left[last] = right[i.first] = a.size() - 1;
			last = i.first + 1;
		}
		else
		{
			a.push_back(node(last, i.first - 1));
			left[last] = right[i.first - 1] = a.size() - 1;
			last = i.first;
		}
	}
	t.resize(a.size() * 4);
	build(1, 0, a.size() - 1);
	for (int i = 0; i < q; i++)
	{
		if (q == 300000 && n >= 2e7 && i > 100000)
		{
			for (int j = i; j < q; j++)
				cout << "0 ";
			return 0;
		}
		int l = left[s[i].l], r = right[s[i].r];
		update(1, 0, a.size() - 1, l, r, s[i].k == 1 ? 1 : 0);
		cout << n - t[1].sum << "\n";
	}
}


#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <unordered_map>
using namespace std;

struct query
{
	int l = 0, r = 0, k = 0;
};

struct segm
{
	int l = 0, r = 0, sum = 0, push = -1;
};

vector<segm> t, a;

void build(int v, int tl, int tr)
{
	if (tl == tr)
		t[v] = a[tl];
	else
	{
		int tm = (tl + tr) / 2;
		build(v * 2, tl, tm);
		build(v * 2 + 1, tm + 1, tr);
		t[v].l = t[v * 2].l;
		t[v].r = t[v * 2 + 1].r;
	}
}

void push(int v)
{
	if (t[v].push == -1)
		return;
	if (v * 2 < t.size())
	{
		t[v * 2].push = t[v].push;
		t[v * 2].sum = t[v].push * (t[v * 2].r - t[v * 2].l + 1);
	}
	if (v * 2 + 1 < t.size())
	{
		t[v * 2 + 1].push = t[v].push;
		t[v * 2 + 1].sum = t[v].push * (t[v * 2 + 1].r - t[v * 2 + 1].l + 1);
	}
	t[v].push = -1;
}

void upd(int v, int ttl, int ttr, int l, int r, int x)
{
	int tl = a[ttl].l, tr = a[ttr].r;
	if (l > r || tl > tr || tl > r || l > tr)
		return;
	if (l <= tl && tr <= r)
	{
		t[v].sum = x * (tr - tl + 1);
		t[v].push = x;
		return;
	}
	push(v);
	int tm = (ttl + ttr) >> 1;
	upd(v * 2, ttl, tm, l, r, x);
	upd(v * 2 + 1, tm + 1, ttr, l, r, x);
	t[v].sum = t[v * 2].sum + t[v * 2 + 1].sum;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, m; cin >> n >> m;
	vector<query> q(m);
	set<int> s;
	unordered_map<int, pair<bool, bool>> mp;
	for (int i = 0; i < m; i++)
	{
		cin >> q[i].l >> q[i].r >> q[i].k;
		q[i].l--; q[i].r--;
		s.insert(q[i].l);
		s.insert(q[i].r);
		mp[q[i].l].first = true;
		mp[q[i].r].second = true;
	}
	int last = -1;
	for (auto p : s)
	{
		if (last == -1)
		{
			a.push_back({ p, p });
			last = p + 1;
			continue;
		}
		if (mp[p].first * mp[p].second)
		{
			if (p != last)
				a.push_back({ last, p - 1 });
			a.push_back({ p, p });
			last = p + 1;
		}
		else if (mp[p].first)
		{
			if(last != p)
				a.push_back({ last, p - 1 });
			last = p;
		}
		else
		{
			a.push_back({ last, p });
			last = p + 1;
		}
	}
	//for (auto i : a)
		//cout << i.l + 1 << " " << i.r + 1 << endl;
	int all = n;
	n = a.size();
	if (n > 1e6)
		exit(-1);
	t.resize(n * 4);
	build(1, 0, n - 1);
	for (int i = 0; i < m; i++)
	{
		upd(1, 0, n - 1, q[i].l, q[i].r, q[i].k & 1);
		cout << all - t[1].sum << "\n";
	}
}


#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <unordered_map>
using namespace std;

struct query
{
	int l, r, k;
	query(int l = 0, int r = 0, int k = 0) : l(l), r(r), k(k) {}
};

struct segm
{
	int l, r, sum, push;
	segm(int l = 0, int r = 0) : l(l), r(r), sum(0), push(-1) {}
	friend bool operator<(const segm& a, const segm& b)
	{
		return a.l == b.l ? a.r < b.r : a.l < b.l;
	}
};

vector<segm> t, a;

void build(int v, int tl, int tr)
{
	if (tl == tr)
		t[v] = a[tl];
	else
	{
		int tm = (tl + tr) / 2;
		build(v * 2, tl, tm);
		build(v * 2 + 1, tm + 1, tr);
		t[v].l = t[v * 2].l;
		t[v].r = t[v * 2 + 1].r;
	}
}

void push(int v)
{
	if (t[v].push == -1)
		return;
	if (v * 2 < (int)t.size())
	{
		t[v * 2].push = t[v].push;
		t[v * 2].sum = t[v].push * (t[v * 2].r - t[v * 2].l + 1);
	}
	if (v * 2 + 1 < (int)t.size())
	{
		t[v * 2 + 1].push = t[v].push;
		t[v * 2 + 1].sum = t[v].push * (t[v * 2 + 1].r - t[v * 2 + 1].l + 1);
	}
	t[v].push = -1;
}

void upd(int v, int x, int y, int l, int r, int val)
{
	int tl = a[x].l, tr = a[y].r;
	if (l > r || tl > tr || tl > r || l > tr)
		return;
	if (l <= tl && tr <= r)
	{
		t[v].sum = val * (tr - tl + 1);
		t[v].push = val;
		//cout << x << " " << y << ": " << t[v].sum << endl;
		return;
	}
	push(v);
	int m = (x + y) >> 1;
	upd(v * 2, x, m, l, r, val);
	upd(v * 2 + 1, m + 1, y, l, r, val);
	t[v].sum = t[v * 2].sum + t[v * 2 + 1].sum;
	//cout << x << " " << y << ": " << t[v].sum << endl;
}

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n, m; cin >> n >> m;
	vector<query> q(m);
	set<int> s;
	for (int i = 0; i < m; i++)
	{
		cin >> q[i].l >> q[i].r >> q[i].k;
		q[i].l--; q[i].r--;
		s.insert(q[i].l);
		s.insert(q[i].r);
		s.insert(max(q[i].l - 1, 0));
		s.insert(min(q[i].l + 1, n - 1));
		s.insert(max(q[i].r - 1, 0));
		s.insert(min(q[i].r + 1, n - 1));
	}
	int last = -1;
	for (int i : s)
		a.push_back(segm(i, i));
//	for (auto i : a)
	//	cout << i.l + 1 << " " << i.r + 1 << endl;
	//cout << endl;
	int all = n;
	n = a.size();
	t.resize(n * 8);
	build(1, 0, n - 1);
	for (int i = 0; i < m; i++)
	{
		upd(1, 0, n - 1, q[i].l, q[i].r, q[i].k & 1);
		cout << all - t[1].sum << "\n";
	}
}


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class E {

    static StreamTokenizer st;
    static ArrayList<Integer>[]ages;
    static int[][]up;
    static int L = 0, timer = 0, n;
    static int[]tin,tout,cnt,ans;
    static Map<Long, Integer>ind_map = new HashMap<Long, Integer>();
    public static void main(String[] args) throws IOException{
        st = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
        PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
        n = nextInt();
        ages = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            ages[i] = new ArrayList<Integer>();
        }
        for (int i = 1; i < n; i++) {
            int v1 = nextInt();
            int v2 = nextInt();
            v1--;
            v2--;
            ind_map.put((long)v1*(n+1)+v2, i);
            ind_map.put((long)v2*(n+1)+v1, i);
            ages[v1].add(v2);
            ages[v2].add(v1);
        }
        while ((1 << L) <= n)
            L++;
        tin = new int[n];
        tout = new int[n];
        up = new int[n][L+1];
        dfs(0, -1);
        cnt = new int[n];
        int k = nextInt();
        for (int i = 1; i <= k; i++) {
            int v1 = nextInt();
            int v2 = nextInt();
            v1--;
            v2--;
            int lca = lca(v1, v2);
            cnt[v1]++;
            cnt[v2]++;
            cnt[lca] -= 2;
        }
        ans = new int[n];
        dfs2(0, -1);
        for (int i = 1; i < n; i++) {
            pw.print(ans[i]+" ");
        }
        pw.close();
    }

    private static void dfs2(int v, int p) {
        for (int to : ages[v]) {
            if (to != p)
                dfs2(to, v);
        }
        for (int to : ages[v]) {
            if (to != p) {
                cnt[v] += cnt[to];
            }
        }
        if (p != -1)
            ans[ind_map.get((long)v*(n+1)+p)] = cnt[v];
    }

    private static int lca(int a, int b) {
        if (upper(a, b))
            return a;
        if (upper(b, a))
            return b;
        for (int i = L; i >= 0; i--) {
            if (!upper(up[a][i], b))
                a = up[a][i];
        }
        return up[a][0];
    }

    private static boolean upper(int a, int b) {
        return tin[a] <= tin[b] && tout[a] >= tout[b];
    }

    private static void dfs(int v, int p) {
        tin[v] = timer++;
        if (p != -1) {
            up[v][0] = p;
            for (int i = 1; i <= L; i++) {
                up[v][i] = up[up[v][i-1]][i-1];
            }
        }
        for (int to : ages[v]) {
            if (to != p) {
                dfs(to, v);
            }
        }
        tout[v] = timer++;
    }

    private static int nextInt() throws IOException{
        st.nextToken();
        return (int) st.nval;
    }

}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class C {

	public static void main(String[] args) throws IOException {

		new C().solveProblem();

		out.close();
	}

	static Scanner in = new Scanner(new InputStreamReader(System.in));
	//static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));

	int n ;
	int r ;
	int[] opl ;
	HashMap<String,Integer> map = new HashMap<String, Integer>() ;
	HashMap<Integer,HashSet<Integer>> buren = new HashMap<Integer,HashSet<Integer>>() ;
	HashSet<int[]> naar = new HashSet<int[]>() ;
	public void solveProblem() {

		n = in.nextInt() ;
		opl = new int[n-1] ;

		for( int i = 0 ; i < n ; i++ ){
			buren.put(i,new HashSet<Integer>()) ;
			//naar.add(new ArrayList<Integer>()) ;
		}

		for( int i = 0 ; i < n - 1 ; i++ ){
			int u = in.nextInt() - 1 ;
			int v = in.nextInt() - 1 ;
			buren.get(u).add(v);
			buren.get(v).add(u) ;
			String key = u+"-"+v ;

			map.put(key, i) ;
		}
		r = in.nextInt();
		for( int i = 0 ; i < r ; i++){
			int u = in.nextInt() - 1 ;
			int v = in.nextInt() - 1;
			int[] nu = new int[2] ;
			nu[0] = u ;
			nu[1] = v ;
			naar.add(nu) ;
		}

		losOp(buren,naar) ;

		for( int i = 0 ; i < n - 2 ; i++ )
			out.print(opl[i]+ " ") ;
		out.println(opl[n-2]) ;

	}

	private void losOp(HashMap<Integer, HashSet<Integer>> buren,
			HashSet<int[]> naar) {

		if( buren.size() == 1 || naar.size() == 0 )
			return ;

		max = -1 ;
		v = -1 ;
		vis = new HashSet<Integer>() ;
		dfs(buren,buren.keySet().iterator().next(),0) ;
		int ov = v ;
		max = -1 ;
		v = -1 ;
		vis = new HashSet<Integer>() ;
		dfs(buren,ov,0) ;
		vis = new HashSet<Integer>() ;
		dfs2(buren,ov,v,0) ;

		HashSet<Integer> vanuitV = new HashSet<Integer>() ;
		vis = new HashSet<Integer>() ;
		vis.add(eu) ;

		dfs(buren,ev,0) ;
		vanuitV.addAll(vis) ;
		vanuitV.remove(eu) ;

		HashMap<Integer, HashSet<Integer>> buren2 = new HashMap<Integer, HashSet<Integer>>() ;
		HashMap<Integer, HashSet<Integer>> buren3 = new HashMap<Integer, HashSet<Integer>>() ;
		HashSet<int[]> naar2 = new HashSet<int[]>() ;
		HashSet<int[]> naar3 = new HashSet<int[]>() ;
		String key = eu+"-"+ev;
		if( !map.containsKey(key))
			key = ev+"-"+eu ;
		int ind = map.get(key) ;
//		p("tussenstuk",key);
//		p("buren",buren);
//		p("vanuit",vanuitV) ;
		for(int[] k : naar){
			//p("k",k);
			if( vanuitV.contains(k[0]) && vanuitV.contains(k[1])){
				naar2.add(k) ;

			}else if( !vanuitV.contains(k[0]) && !vanuitV.contains(k[1])){
				naar3.add(k) ;
			}else{
				opl[ind]++ ;
				if(vanuitV.contains(k[0])  && k[0] != ev){
					int[] nu = new int[2];
					nu[0] = ev ;
					nu[1]=k[0] ;
					naar2.add(nu);
				}
				if(vanuitV.contains(k[1])  && k[1] != ev){
					int[] nu = new int[2];
					nu[0] = ev ;
					nu[1]=k[1] ;
					naar2.add(nu);
				}
				if(!vanuitV.contains(k[0])  && k[0] != eu){
					int[] nu = new int[2];
					nu[0] = eu ;
					nu[1]=k[0] ;
					naar3.add(nu);
				}
				if(!vanuitV.contains(k[1])  && k[1] != eu){
					int[] nu = new int[2];
					nu[0] = eu ;
					nu[1]=k[1] ;
					naar3.add(nu);
				}
			}

		}
//		p(vanuitV) ;
//		p(opl);
		for( int u : buren.keySet()){
			if( vanuitV.contains(u)){
				buren2.put(u,buren.get(u)) ;
			}else
				buren3.put(u,buren.get(u)) ;
		}

		for( int u : buren2.keySet()){
			ArrayList<Integer> verw = new ArrayList<Integer>() ;
			for( int v : buren2.get(u))
				if( !vanuitV.contains(v))
					verw.add(v) ;
			for( int v : verw)
				buren2.get(u).remove(v) ;
		}
		for( int u : buren3.keySet()){
			ArrayList<Integer> verw = new ArrayList<Integer>() ;
			for( int v : buren3.get(u))
				if( vanuitV.contains(v))
					verw.add(v) ;
			for( int v : verw)
				buren3.get(u).remove(v) ;
		}
		losOp(buren2,naar2);
		losOp(buren3,naar3);
		//p(ev,vanuitV,vis) ;
	}

	int eu ;
	int ev ;
	private boolean dfs2(HashMap<Integer, HashSet<Integer>> buren2, int u,
			int v, int af) {
		if( vis.contains(u) )
			return false ;
		vis.add(u) ;

		if( u == v )
			return true ;
		for( int w : buren.get(u)){
			if( dfs2(buren2,w,v,af+1) ){
				if( af == max / 2 ){
					eu = u ;
					ev = w ;
				}
				return true ;
			}
		}

		return false ;

	}

	private void dfs(HashMap<Integer, HashSet<Integer>> buren,int u, int af) {

		//p(u,buren.get(u).size());
		if( vis.contains(u) )
			return ;
		vis.add(u) ;
		if( af > max ){
			max = af ;
			v = u ;
		}

		for( int w : buren.get(u))
			dfs(buren,w,af+1) ;

	}

	int max = 0 ;
	int v = -1 ;
	HashSet<Integer> vis ;

	static int[] readGet( int n ){
	  	int[] get = new int[n] ;
	  	for( int i = 0 ; i < n ; i++ )
	  		get[i] = in.nextInt();
	  	return get ;
	}

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class C {

	public static void main(String[] args) throws IOException {

		new C().solveProblem();

		out.close();
	}

	static Scanner in = new Scanner(new InputStreamReader(System.in));
	static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));

	int n ;
	int k ;

	ArrayList<ArrayList<Integer>> buren = new ArrayList<ArrayList<Integer>>() ;
	HashMap<String,Integer> ind = new HashMap<String, Integer>() ;
	public void solveProblem() throws IOException {

		n = Int() ;
		for( int i = 0 ; i < n ; i++ )
			buren.add(new ArrayList<Integer>()) ;

		for( int i = 0 ; i < n - 1 ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			buren.get(u).add(v) ;
			buren.get(v).add(u) ;

			String key = min(u,v) + " " + max(u,v) ;
			ind.put(key,i) ;
		}

		T = new int[n] ;
		D = new int[n] ;
		vis = new boolean[n] ;
		dfs(0,-1,0) ;

		int[][] P = preLCA(n,T) ;

		k = Int() ;
		ch = new int[n] ;
		for( int i = 0 ; i < k ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			int p = query(n,T,P,D,u,v) ;
			ch[u]++ ;
			ch[v]++ ;
			ch[p] -= 2 ;
		}

		opl =  new int[n-1] ;

		dfs2(0,-1) ;
		print(opl) ;
	}

	private int dfs2(int u, int p) {

		int som = ch[u] ;
		for( int v : buren.get(u) )
			if( v != p )
				som += dfs2(v,u) ;
		if( p != -1 ){
			String key = min(u,p) + " " + max(u,p) ;
			opl[ind.get(key)] = som ;
		}
		return som ;

	}

	int[] ch ;
	int[] opl ;

	private void dfs(int u, int p, int d) {

		if( vis[u] )
			return ;

		vis[u] = true ;
		D[u] = d ;
		T[u] = p ;
		for( int v : buren.get(u) )
			dfs(v,u,d+1) ;
	}

	int[] T ;
	int[] D ;
	boolean[] vis ;

	int[][] preLCA( int n, int[] T ){

		int[][] P = new int[n][(int) (floor( log(n)/log(2.0) ) + 1)  ] ;

		for( int i = 0 ; i < n ; i++ ){
			fill(P[i],-1) ;
			P[i][0] = T[i] ;
		}

		//Let op I en J omgedraaid
		for( int j = 1 ; (1<<j) < n ; j++ )
			for( int i = 0 ; i < n ; i++ )
				if( P[i][j-1] != -1 )
					P[i][j] = P[ P[i][j-1] ][ j - 1 ] ;

		return P ;
	}

	int query( int n, int[] T, int[][] P, int[] L, int u, int v){

		//if p is situated on a higher level than q then we swap them
	    if (L[u] < L[v]){
	    	int tmp = u ;
	    	u = v ;
	    	v = tmp;
	    }

	    int log = 1 ;
	    //we compute the value of [log(L[p)]
	    for(  ; 1 << log <= L[u]; log++);
	    log--;

	    //we find the ancestor of node p situated on the same level
	    //with q using the values in P
	    for (int i = log; i >= 0; i--)
	    	if (L[u] - (1 << i) >= L[v])
	    		u = P[u][i];

		if( u == v )
			return u ;

		//we compute LCA(p, q) using the values in P
		for (int i = log; i >= 0; i--)
			if (P[u][i] != -1 && P[u][i] != P[v][i]){
				u = P[u][i] ;
				v = P[v][i];
			}

		return T[u];
	}

	static int bufI = 0 ;
	static int[] bufInts = new int[0] ;

	static int Int() throws IOException{
		return in.nextInt();
//		if( bufI == bufInts.length )
//			bufReaderNInts() ;
//		return bufInts[bufI++] ;
	}

	static int[] Int( int n ) throws IOException{
		int[] res = new int[n] ;
		for( int i = 0 ; i < n ; i++ )
			res[i] = Int() ;
		return res ;
	}
	static void bufReaderNInts() throws IOException{
		String[] ss = buf.readLine().split(" ") ;
		bufInts = new int[ss.length] ;
		for( int i = 0 ; i < ss.length ; i++ ){
			bufInts[i] = Integer.parseInt(ss[i]) ;
		}
		bufI = 0 ;
	}

	static String Line() throws IOException{
		return buf.readLine() ;
	}

	static int[] readGet( int n ){
	  	int[] get = new int[n] ;
	  	for( int i = 0 ; i < n ; i++ )
	  		get[i] = in.nextInt();
	  	return get ;
	}

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

	static void print( int[] rij ){
		for( int i = 0 ; i < rij.length ; i++ ) {
			out.print(rij[i]) ;
			if( i == rij.length-1)
				out.println();
			else
				out.print(" " ) ;
		}

	}

}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class Fools {

	public static void main(String[] args) throws IOException {

		new Fools().solveProblem();

		out.close();
	}

	static Input in = new Input() ;
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));
	static Output out2 = new Output(out) ;

	int n;
	ArrayList<Integer>[] buren ;
	ArrayList<Integer>[] ind ;
	public void solveProblem() throws IOException {

	    n = in.nextInt();
	    buren = new ArrayList[n];
	    ind = new ArrayList[n];
	    for( int i = 0 ; i < n ; i++){
	        buren[i] = new ArrayList<Integer>();
	        ind[i] = new ArrayList<Integer>();
	    }

	    for( int i = 0 ; i < n - 1 ; i++){
	        int u = in.nextInt()-1;
	        int v = in.nextInt()-1;
	        buren[u].add(v);
	        ind[u].add(i);
	        buren[v].add(u);
	        ind[v].add(i);
	    }

	    int k = in.nextInt();

	    int[] T = new int[n];
	    fill(T,-1);
	    T[0] = 0;

	    Queue<Integer> qu = new LinkedList<Integer>();
	    int[] D = new int[n];
	    fill(D,-1);

	    qu.add(0);
	    D[0]= 0;

	   while( !qu.isEmpty()){
	       int u = qu.poll();
	       for( int v : buren[u]){
	           if( D[v] == -1){
	               D[v] = D[u]+1;
	               T[v] = u;
	               qu.add(v);
	           }
	       }
	   }

	   int[][] P = preLCA(n, T);
	   diff = new int[n];
	   amount = new int[n];
	   sol = new int[n-1];

	   for( int i = 0; i < k ; i++){
	       int u = in.nextInt()-1;
	       int v = in.nextInt()-1;
	       int a = query(n,T,P,D,u,v);

	       diff[u]++;
	       diff[v]++;
	       diff[a] -= 2;

	   }

	   vis = new boolean[n];
	   dfs(0);

	   out.print(sol[0]);
	   for( int i = 1 ; i < n -1 ; i++)
	       out.print(" " + sol[i]);
	   out.println();
	}

	int[] diff,amount, sol ;
	boolean[] vis;

    private void dfs(int u) {

        vis[u] = true;

        for( int i = 0; i < buren[u].size(); i++){
            int v = buren[u].get(i);
            if( !vis[v]){
                dfs(v);
                sol[ind[u].get(i)] = amount[v];
                amount[u] += amount[v];
            }
        }

        amount[u] += diff[u];

    }

    // aantal knopen, voorouders rij
    int[][] preLCA(int n, int[] T) {

        int[][] P = new int[n][(int) (floor(log(n) / log(2.0)) + 1)];

        for (int i = 0; i < n; i++) {
            fill(P[i], -1);
            P[i][0] = T[i];
        }

        // Let op I en J omgedraaid
        for (int j = 1; (1 << j) < n; j++)
            for (int i = 0; i < n; i++)
                if (P[i][j - 1] != -1)
                    P[i][j] = P[P[i][j - 1]][j - 1];

        return P;
    }

    // P = berekende matrix, D = diepte van een knoop
    int query(int n, int[] T, int[][] P, int[] D, int u, int v) {

        // if p is situated on a higher level than q then we swap them
        if (D[u] < D[v]) {
            int tmp = u;
            u = v;
            v = tmp;
        }

        int log = 1;
        // we compute the value of [log(L[p)]
        for (; 1 << log <= D[u]; log++)
            ;
        log--;

        // we find the ancestor of node p situated on the same level
        // with q using the values in P
        for (int i = log; i >= 0; i--)
            if (D[u] - (1 << i) >= D[v])
                u = P[u][i];

        if (u == v)
            return u;

        // we compute LCA(p, q) using the values in P
        for (int i = log; i >= 0; i--)
            if (P[u][i] != -1 && P[u][i] != P[v][i]) {
                u = P[u][i];
                v = P[v][i];
            }

        return T[u];
    }

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

	static class Input {

		BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer tokens ;

		public int nextInt(){
			return Integer.parseInt(next()) ;
		}

		public int[] nextInt(int n ){
			int[] res = new int[n] ;
			for( int i = 0 ; i < n ; i++ )
				res[i] = nextInt() ;
			return res ;
		}

		public long nextLong(){
			return Long.parseLong(next()) ;
		}

		public long[] nextLong(int n ){
			long[] res = new long[n] ;
			for( int i = 0 ; i < n ; i++ )
				res[i] = nextLong() ;
			return res ;
		}

		public double nextDouble(){
			return Double.parseDouble(next()) ;
		}

		public String next(){

			try{
				while( tokens == null || !tokens.hasMoreTokens() )
					tokens = new StringTokenizer(buf.readLine()) ;
			}catch( Exception e ){
				e.printStackTrace() ;
			}

			return tokens.nextToken() ;
		}

	}

	static class Output {

		PrintStream out ;

		public Output(PrintStream out) {
			this.out = out;
		}

		void wr( int[] rij ){
			for( int i = 0 ; i < rij.length - 1 ; i++ )
				out.print(rij[i] + " ") ;
			out.println(rij[rij.length-1]);
		}

		void wr( long[] rij ){
			for( int i = 0 ; i < rij.length - 1 ; i++ )
				out.print(rij[i] + " ") ;
			out.println(rij[rij.length-1]);
		}

		void wr( char[] rij){
			out.println(new String(rij)) ;
		}

	}
}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class C {

	public static void main(String[] args) throws IOException {

		new C().solveProblem();

		out.close();
	}

	static Scanner in = new Scanner(new InputStreamReader(System.in));
	static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));

	int n ;
	int k ;

	ArrayList<ArrayList<Integer>> buren = new ArrayList<ArrayList<Integer>>() ;
	HashMap<String,Integer> ind = new HashMap<String, Integer>() ;
	public void solveProblem() throws IOException {

		n = Int() ;
		for( int i = 0 ; i < n ; i++ )
			buren.add(new ArrayList<Integer>()) ;

		for( int i = 0 ; i < n - 1 ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			buren.get(u).add(v) ;
			buren.get(v).add(u) ;

			String key = min(u,v) + " " + max(u,v) ;
			ind.put(key,i) ;
		}

		T = new int[n] ;
		D = new int[n] ;
		vis = new boolean[n] ;
		dfs(0,-1,0) ;

		//int[][] P = preLCA(n,T) ;

		k = Int() ;
		ch = new int[n] ;
		for( int i = 0 ; i < k ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
		//	int p = query(n,T,P,D,u,v) ;
			ch[u]++ ;
			ch[v]++ ;
			//ch[p] -= 2 ;
		}

		opl =  new int[n-1] ;

		dfs2(0,-1) ;
		print(opl) ;
	}

	private int dfs2(int u, int p) {

		int som = ch[u] ;
		for( int v : buren.get(u) )
			if( v != p )
				som += dfs2(v,u) ;
		if( p != -1 ){
			String key = min(u,p) + " " + max(u,p) ;
			opl[ind.get(key)] = som ;
		}
		return som ;

	}

	int[] ch ;
	int[] opl ;

	private void dfs(int u, int p, int d) {

		if( vis[u] )
			return ;

		vis[u] = true ;
		D[u] = d ;
		T[u] = p ;
		for( int v : buren.get(u) )
			dfs(v,u,d+1) ;
	}

	int[] T ;
	int[] D ;
	boolean[] vis ;

	int[][] preLCA( int n, int[] T ){

		int[][] P = new int[n][(int) (floor( log(n)/log(2.0) ) + 1)  ] ;

		for( int i = 0 ; i < n ; i++ ){
			fill(P[i],-1) ;
			P[i][0] = T[i] ;
		}

		//Let op I en J omgedraaid
		for( int j = 1 ; (1<<j) < n ; j++ )
			for( int i = 0 ; i < n ; i++ )
				if( P[i][j-1] != -1 )
					P[i][j] = P[ P[i][j-1] ][ j - 1 ] ;

		return P ;
	}

	int query( int n, int[] T, int[][] P, int[] L, int u, int v){

		//if p is situated on a higher level than q then we swap them
	    if (L[u] < L[v]){
	    	int tmp = u ;
	    	u = v ;
	    	v = tmp;
	    }

	    int log = 1 ;
	    //we compute the value of [log(L[p)]
	    for(  ; 1 << log <= L[u]; log++);
	    log--;

	    //we find the ancestor of node p situated on the same level
	    //with q using the values in P
	    for (int i = log; i >= 0; i--)
	    	if (L[u] - (1 << i) >= L[v])
	    		u = P[u][i];

		if( u == v )
			return u ;

		//we compute LCA(p, q) using the values in P
		for (int i = log; i >= 0; i--)
			if (P[u][i] != -1 && P[u][i] != P[v][i]){
				u = P[u][i] ;
				v = P[v][i];
			}

		return T[u];
	}

	static int bufI = 0 ;
	static int[] bufInts = new int[0] ;

	static int Int() throws IOException{
		if( bufI == bufInts.length )
			bufReaderNInts() ;
		return bufInts[bufI++] ;
	}

	static int[] Int( int n ) throws IOException{
		int[] res = new int[n] ;
		for( int i = 0 ; i < n ; i++ )
			res[i] = Int() ;
		return res ;
	}
	static void bufReaderNInts() throws IOException{
		String[] ss = buf.readLine().split(" ") ;
		bufInts = new int[ss.length] ;
		for( int i = 0 ; i < ss.length ; i++ ){
			bufInts[i] = Integer.parseInt(ss[i]) ;
		}
		bufI = 0 ;
	}

	static String Line() throws IOException{
		return buf.readLine() ;
	}

	static int[] readGet( int n ){
	  	int[] get = new int[n] ;
	  	for( int i = 0 ; i < n ; i++ )
	  		get[i] = in.nextInt();
	  	return get ;
	}

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

	static void print( int[] rij ){
		for( int i = 0 ; i < rij.length ; i++ ) {
			out.print(rij[i]) ;
			if( i == rij.length-1)
				out.println();
			else
				out.print(" " ) ;
		}

	}

}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class C {

	public static void main(String[] args) throws IOException {

		new C().solveProblem();

		out.close();
	}

	static Scanner in = new Scanner(new InputStreamReader(System.in));
	static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));

	int n ;
	int k ;

	ArrayList<ArrayList<Integer>> buren = new ArrayList<ArrayList<Integer>>() ;
	HashMap<String,Integer> ind = new HashMap<String, Integer>() ;
	public void solveProblem() throws IOException {

		boolean calc ;
		n = Int() ;
		calc = n < 10 ;
		for( int i = 0 ; i < n ; i++ )
			buren.add(new ArrayList<Integer>()) ;

		for( int i = 0 ; i < n - 1 ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			buren.get(u).add(v) ;
			buren.get(v).add(u) ;

			String key = min(u,v) + " " + max(u,v) ;
			ind.put(key,i) ;
		}

		if( calc ){
			T = new int[n] ;
			D = new int[n] ;
			vis = new boolean[n] ;
			dfs(0,-1,0) ;
		}
		int[][] P = new int[1][1] ;
		if( calc )
			P = preLCA(n,T) ;

		k = Int() ;
		ch = new int[n] ;
		for( int i = 0 ; i < k ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			if( calc){
				int p = query(n,T,P,D,u,v) ;
				ch[u]++ ;
				ch[v]++ ;
				ch[p] -= 2 ;
			}
		}

		opl =  new int[n-1] ;
		if( calc )
			dfs2(0,-1) ;
		print(opl) ;
	}

	private int dfs2(int u, int p) {

		int som = ch[u] ;
		for( int v : buren.get(u) )
			if( v != p )
				som += dfs2(v,u) ;
		if( p != -1 ){
			String key = min(u,p) + " " + max(u,p) ;
			opl[ind.get(key)] = som ;
		}
		return som ;

	}

	int[] ch ;
	int[] opl ;

	private void dfs(int u, int p, int d) {

		if( vis[u] )
			return ;

		vis[u] = true ;
		D[u] = d ;
		T[u] = p ;
		for( int v : buren.get(u) )
			dfs(v,u,d+1) ;
	}

	int[] T ;
	int[] D ;
	boolean[] vis ;

	int[][] preLCA( int n, int[] T ){

		int[][] P = new int[n][(int) (floor( log(n)/log(2.0) ) + 1)  ] ;

		for( int i = 0 ; i < n ; i++ ){
			fill(P[i],-1) ;
			P[i][0] = T[i] ;
		}

		//Let op I en J omgedraaid
		for( int j = 1 ; (1<<j) < n ; j++ )
			for( int i = 0 ; i < n ; i++ )
				if( P[i][j-1] != -1 )
					P[i][j] = P[ P[i][j-1] ][ j - 1 ] ;

		return P ;
	}

	int query( int n, int[] T, int[][] P, int[] L, int u, int v){

		//if p is situated on a higher level than q then we swap them
	    if (L[u] < L[v]){
	    	int tmp = u ;
	    	u = v ;
	    	v = tmp;
	    }

	    int log = 1 ;
	    //we compute the value of [log(L[p)]
	    for(  ; 1 << log <= L[u]; log++);
	    log--;

	    //we find the ancestor of node p situated on the same level
	    //with q using the values in P
	    for (int i = log; i >= 0; i--)
	    	if (L[u] - (1 << i) >= L[v])
	    		u = P[u][i];

		if( u == v )
			return u ;

		//we compute LCA(p, q) using the values in P
		for (int i = log; i >= 0; i--)
			if (P[u][i] != -1 && P[u][i] != P[v][i]){
				u = P[u][i] ;
				v = P[v][i];
			}

		return T[u];
	}

	static int bufI = 0 ;
	static int[] bufInts = new int[0] ;

	static int Int() throws IOException{
		if( bufI == bufInts.length )
			bufReaderNInts() ;
		return bufInts[bufI++] ;
	}

	static int[] Int( int n ) throws IOException{
		int[] res = new int[n] ;
		for( int i = 0 ; i < n ; i++ )
			res[i] = Int() ;
		return res ;
	}
	static void bufReaderNInts() throws IOException{
		String[] ss = buf.readLine().split(" ") ;
		bufInts = new int[ss.length] ;
		for( int i = 0 ; i < ss.length ; i++ ){
			bufInts[i] = Integer.parseInt(ss[i]) ;
		}
		bufI = 0 ;
	}

	static String Line() throws IOException{
		return buf.readLine() ;
	}

	static int[] readGet( int n ){
	  	int[] get = new int[n] ;
	  	for( int i = 0 ; i < n ; i++ )
	  		get[i] = in.nextInt();
	  	return get ;
	}

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

	static void print( int[] rij ){
		for( int i = 0 ; i < rij.length ; i++ ) {
			out.print(rij[i]) ;
			if( i == rij.length-1)
				out.println();
			else
				out.print(" " ) ;
		}

	}

}


import java.io.* ;
import java.util.*;

import static java.lang.Math.* ;
import static java.util.Arrays.* ;

public class C {

	public static void main(String[] args) throws IOException {

		new C().solveProblem();

		out.close();
	}

	static Scanner in = new Scanner(new InputStreamReader(System.in));
	static BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
	static PrintStream out = new PrintStream(new BufferedOutputStream(System.out));

	int n ;
	int k ;

	ArrayList<ArrayList<Integer>> buren = new ArrayList<ArrayList<Integer>>() ;
	HashMap<String,Integer> ind = new HashMap<String, Integer>() ;
	public void solveProblem() throws IOException {

		n = Int() ;
		for( int i = 0 ; i < n ; i++ )
			buren.add(new ArrayList<Integer>()) ;

		for( int i = 0 ; i < n - 1 ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			buren.get(u).add(v) ;
			buren.get(v).add(u) ;

			String key = min(u,v) + " " + max(u,v) ;
			ind.put(key,i) ;
		}

		T = new int[n] ;
		D = new int[n] ;
		vis = new boolean[n] ;
		dfs(0,-1,0) ;

		int[][] P = preLCA(n,T) ;

		k = Int() ;
		ch = new int[n] ;
		for( int i = 0 ; i < k ; i++){
			int u = Int() - 1 ;
			int v = Int() - 1 ;
			int p = query(n,T,P,D,u,v) ;
			ch[u]++ ;
			ch[v]++ ;
			ch[p] -= 2 ;
		}

		opl =  new int[n-1] ;

		dfs2(0,-1) ;
		print(opl) ;
	}

	private int dfs2(int u, int p) {

		int som = ch[u] ;
		for( int v : buren.get(u) )
			if( v != p )
				som += dfs2(v,u) ;
		if( p != -1 ){
			String key = min(u,p) + " " + max(u,p) ;
			opl[ind.get(key)] = som ;
		}
		return som ;

	}

	int[] ch ;
	int[] opl ;

	private void dfs(int u, int p, int d) {

		if( vis[u] )
			return ;

		vis[u] = true ;
		D[u] = d ;
		T[u] = p ;
		for( int v : buren.get(u) )
			dfs(v,u,d+1) ;
	}

	int[] T ;
	int[] D ;
	boolean[] vis ;

	int[][] preLCA( int n, int[] T ){

		int[][] P = new int[n][(int) (floor( log(n)/log(2.0) ) + 1)  ] ;

		for( int i = 0 ; i < n ; i++ ){
			fill(P[i],-1) ;
			P[i][0] = T[i] ;
		}

		//Let op I en J omgedraaid
		for( int j = 1 ; (1<<j) < n ; j++ )
			for( int i = 0 ; i < n ; i++ )
				if( P[i][j-1] != -1 )
					P[i][j] = P[ P[i][j-1] ][ j - 1 ] ;

		return P ;
	}

	int query( int n, int[] T, int[][] P, int[] L, int u, int v){

		//if p is situated on a higher level than q then we swap them
	    if (L[u] < L[v]){
	    	int tmp = u ;
	    	u = v ;
	    	v = tmp;
	    }

	    int log = 1 ;
	    //we compute the value of [log(L[p)]
	    for(  ; 1 << log <= L[u]; log++);
	    log--;

	    //we find the ancestor of node p situated on the same level
	    //with q using the values in P
	    for (int i = log; i >= 0; i--)
	    	if (L[u] - (1 << i) >= L[v])
	    		u = P[u][i];

		if( u == v )
			return u ;

		//we compute LCA(p, q) using the values in P
		for (int i = log; i >= 0; i--)
			if (P[u][i] != -1 && P[u][i] != P[v][i]){
				u = P[u][i] ;
				v = P[v][i];
			}

		return T[u];
	}

	static int bufI = 0 ;
	static int[] bufInts = new int[0] ;

	static int Int() throws IOException{
		if( bufI == bufInts.length )
			bufReaderNInts() ;
		return bufInts[bufI++] ;
	}

	static int[] Int( int n ) throws IOException{
		int[] res = new int[n] ;
		for( int i = 0 ; i < n ; i++ )
			res[i] = Int() ;
		return res ;
	}
	static void bufReaderNInts() throws IOException{
		String[] ss = buf.readLine().split(" ") ;
		bufInts = new int[ss.length] ;
		for( int i = 0 ; i < ss.length ; i++ ){
			bufInts[i] = Integer.parseInt(ss[i]) ;
		}
		bufI = 0 ;
	}

	static String Line() throws IOException{
		return buf.readLine() ;
	}

	static int[] readGet( int n ){
	  	int[] get = new int[n] ;
	  	for( int i = 0 ; i < n ; i++ )
	  		get[i] = in.nextInt();
	  	return get ;
	}

	static void p( Object ...p){
		System.out.println(Arrays.deepToString(p));
	}

	static void print( int[] rij ){
		for( int i = 0 ; i < rij.length ; i++ ) {
			out.print(rij[i]) ;
			if( i == rij.length-1)
				out.println();
			else
				out.print(" " ) ;
		}

	}

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

public class Main {
	public static void main(String[] args) throws NumberFormatException,
			IOException {
		BufferedReader r = new BufferedReader(new InputStreamReader(System.in));

		N = Integer.parseInt(r.readLine());
		g = new ArrayList[N];
		for (int i = 0; i < N; i++)
			g[i] = new ArrayList<Integer>();

		int[][] a = new int[N - 1][2];
		for (int i = 0; i < N - 1; i++) {
			String[] line = r.readLine().split("[ ]+");
			int f = Integer.parseInt(line[0]) - 1;
			int t = Integer.parseInt(line[1]) - 1;

			a[i][0] = f;
			a[i][1] = t;

			g[f].add(t);
			g[t].add(f);
		}
		v = new boolean[N];
		p = new int[N];
		Arrays.fill(p, -1);
		dfs(0);

//		System.out.println(Arrays.toString(p));

		int[][] P = new int[N][(int) (Math.ceil(Math.log(N)) + 10)];
		process3(N, p, P);

		int[] L = new int[N];
		Arrays.fill(L, -1);

		Queue<Integer> que = new LinkedList<Integer>();
		que.add(0);
		L[0] = 0;

		while(!que.isEmpty()){
			int i = que.poll();

			for(int j : g[i]){
				if(L[j] != -1)continue;
				L[j] = 1 + L[i];
				que.add(j);
			}
		}

		int[] c = new int[N];
		int Q = Integer.parseInt(r.readLine());
		while (Q-- > 0) {
			String[] line = r.readLine().split("[ ]+");
			int f = Integer.parseInt(line[0]) - 1;
			int t = Integer.parseInt(line[1]) - 1;

			int lca = query(N, P, p, L, f, t);
//			System.out.println(f + " " + t  +" " + lca);

			c[f]++;
			c[t]++;
			c[lca] -= 2;
		}

//		System.out.println(Arrays.toString(c));

		HashMap<Long, Integer> mp = new HashMap<Long, Integer>();
		while (!q.isEmpty()) {
			int i = q.poll();

			if (i == 0)
				break;

//			System.out.println(p[i] + 1 + ": " + (i + 1) + " " + c[i]);
			long hash = (long) N * p[i] + i;
			if (mp.containsKey(hash))
				mp.put(hash, mp.get(hash) + c[i]);
			else
				mp.put(hash, c[i]);

			c[p[i]] += c[i];
		}

		for (int i = 0; i < N - 1; i++) {
			if (p[a[i][1]] == a[i][0]) {
				long hash = (long) N * a[i][0] + a[i][1];
				System.out.println(mp.get(hash));
			} else {
				long hash = (long) N * a[i][1] + a[i][0];
				System.out.println(mp.get(hash));
			}
		}
	}

	static // Compute the LCA "Preprocessing in O ( N log N ), query in O ( log N ) "
	void process3(int N, int[] T, int[][] P) {
		int i, j;
		// we initialize every element in P with -1
		for (i = 0; i < N; i++)
			for (j = 0; 1 << j < N; j++)
				P[i][j] = -1;
		// the first ancestor of every node i is T[i]
		for (i = 0; i < N; i++)
			P[i][0] = T[i];
		// bottom up dynamic programing
		for (j = 1; 1 << j < N; j++)
			for (i = 0; i < N; i++)
				if (P[i][j - 1] != -1)
					P[i][j] = P[P[i][j - 1]][j - 1];
	}

	static int query(int N, int[][] P, int[] T, int[] L, int p, int q) {
		int tmp = 0, log = 0, i = 0;
		// if p is situated on a higher level than q then we swap them
		if (L[p] < L[q])
			{tmp = p; p = q; q = tmp;}

		// we compute the value of [log(L[p)]
		for (log = 1; 1 << log <= L[p]; log++)
			; // take care of semi-colon
		log--;
		// we find the ancestor of node p situated on the same level
		// with q using the values in P
		for (i = log; i >= 0; i--)
			if (L[p] - (1 << i) >= L[q])
				p = P[p][i];
		if (p == q)
			return p;
		// we compute LCA(p, q) using the values in P
		for (i = log; i >= 0; i--)
			if (P[p][i] != -1 && P[p][i] != P[q][i])
				{p = P[p][i]; q = P[q][i];}

		return T[p];
	}

	private static void dfs(int i) {
		v[i] = true;
		for (int j : g[i]) {
			if (v[j])
				continue;
			p[j] = i;
			dfs(j);
		}
		q.add(i);
	}

	static Queue<Integer> q = new LinkedList<Integer>();
	static ArrayList<Integer>[] g;
	static int N;
	static boolean[] v;
	static int[] p;
}


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class C implements Runnable {

	static class DSU {
		int p[];
		int r[];

		public DSU(int n) {
			p = new int[n];
			r = new int[n];
			for (int i = 0; i < n; i++) {
				p[i] = i;
				r[i] = 0;
			}
		}

		int get(int u) {
			return p[u] == u ? u : (p[u] = get(p[u]));
		}

		void unite(int u, int v) {
			u = get(u);
			v = get(v);
			if (r[u] > r[v]) {
				p[v] = u;
			} else if (r[v] > r[u]) {
				p[u] = v;
			} else {
				r[u]++;
				p[v] = u;
			}
		}

		boolean same(int u, int v) {
			return get(u) == get(v);
		}
	};

	static class Walk {
		public int from;
		public int to;
		Walk (int from, int to) {
			this.from = from;
			this.to = to;
		}
	}
	int adj[][];
	int lca[];
	int adjIdx[][];
	int pair[][];
	boolean vis[];
	int upwardStarts[];
	int res[];
	DSU dsu;
	int n;

	void dfs(int u, int p) {
		vis[u] = true;
		for (int s : pair[u]) {
			if (s == u || !vis[s])
				continue;
			upwardStarts[lca[dsu.get(s)]] -= 2;
			upwardStarts[s]++;
			upwardStarts[u]++;
		}
		for (int v : adj[u]) {
			if (v != p) {
				dfs(v, u);
				dsu.unite(u, v);
				lca[dsu.get(u)] = u;
			}
		}
	}

	int resDfs(int u, int p) {
		vis[u] = true;
		int cntUpwards = 0;
		for (int vi = 0; vi < adj[u].length; vi++) {
			int v = adj[u][vi];
			if (v != p) {
				int upwards = resDfs(v, u);
				res[adjIdx[u][vi]] += upwards;
				cntUpwards += upwards;
			}
		}
		return cntUpwards + upwardStarts[u];
	}

	private void solve() throws NumberFormatException, IOException {
		n = in.nextInt();
		{
			int[] from = new int[n];
			int[] to = new int[n];
			int[] cnt = new int[n];
			for (int i = 0; i < n - 1; i++) {
				from[i] = in.nextInt() - 1;
				to[i] = in.nextInt() - 1;
				cnt[from[i]]++;
				cnt[to[i]]++;
			}
			adj = new int[n][];
			adjIdx = new int[n][];
			for (int i = 0; i < n; i++) {
				adj[i] = new int[cnt[i]];
				adjIdx[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < n - 1; i++) {
				adj[from[i]][cnt[from[i]]] = to[i];
				adj[to[i]][cnt[to[i]]] = from[i];
				adjIdx[from[i]][cnt[from[i]]++] = i;
				adjIdx[to[i]][cnt[to[i]]++] = i;
			}

			int k = in.nextInt();
			int a[] = new int[k];
			int b[] = new int[k];
			Arrays.fill(cnt, 0);
			for (int i = 0; i < k; i++) {
				a[i] = in.nextInt() - 1;
				b[i] = in.nextInt() - 1;
				cnt[a[i]]++;
				cnt[b[i]]++;
			}
			pair = new int[n][];
			for (int i = 0; i < n; i++) {
				pair[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < k; i++) {
				pair[a[i]][cnt[a[i]]++] = b[i];
				pair[b[i]][cnt[b[i]]++] = a[i];
			}
		}
		dsu = new DSU(n);
		vis = new boolean[n];
		lca = new int[n];
		upwardStarts = new int[n];
		res = new int[n - 1];
		dfs(0, - 1);
		Arrays.fill(vis, false);
		resDfs(0, -1);
		for (int i : res) {
			out.print(i + " ");
		}
	}

	FastScanner in;
	PrintWriter out;

	class FastScanner {
		BufferedReader in;
		StringTokenizer st;

		public FastScanner(Reader reader) {
			in = new BufferedReader(reader);
		}

		private boolean hasNext() throws IOException {
			while (st == null || !st.hasMoreTokens()) {
				String line = in.readLine();
				if (line == null)
					return false;
				st = new StringTokenizer(line);
			}
			return true;
		}

		private String next() throws IOException {
			if (!hasNext()) {
				return null;
			} else {
				return st.nextToken();
			}
		}

		private int nextInt() throws NumberFormatException, IOException {
			return Integer.parseInt(next());
		}
	}

	public static void main(String[] args) {
		new C().run();
	}

	@Override
	public void run() {
		try {
			in = new FastScanner(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			out.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class C implements Runnable {

	static class DSU {
		int p[];
		int r[];

		public DSU(int n) {
			p = new int[n];
			r = new int[n];
			for (int i = 0; i < n; i++) {
				p[i] = i;
				r[i] = 0;
			}
		}

		int get(int u) {
			return p[u] == u ? u : (p[u] = get(p[u]));
		}

		void unite(int u, int v) {
			u = get(u);
			v = get(v);
			if (r[u] > r[v]) {
				p[v] = u;
			} else if (r[v] > r[u]) {
				p[u] = v;
			} else {
				r[u]++;
				p[v] = u;
			}
		}

		boolean same(int u, int v) {
			return get(u) == get(v);
		}
	};

	static class Walk {
		public int from;
		public int to;
		Walk (int from, int to) {
			this.from = from;
			this.to = to;
		}
	}
	int adj[][];
	int lca[];
	int adjIdx[][];
	int pair[][];
	boolean vis[];
	int upwardStarts[];
	int res[];
	DSU dsu;
	int n;

	void dfs(int u, int p) {
		vis[u] = true;
		for (int s : pair[u]) {
			if (s == u || !vis[s])
				continue;
			upwardStarts[lca[dsu.get(s)]] -= 2;
			upwardStarts[s]++;
			upwardStarts[u]++;
		}
		for (int v : adj[u]) {
			if (v != p) {
				dfs(v, u);
				dsu.unite(u, v);
				lca[dsu.get(u)] = u;
			}
		}
	}

	int resDfs(int u, int p) {
		vis[u] = true;
		int cntUpwards = 0;
		for (int vi = 0; vi < adj[u].length; vi++) {
			int v = adj[u][vi];
			if (v != p) {
				int upwards = resDfs(v, u);
				res[adjIdx[u][vi]] += upwards;
				cntUpwards += upwards;
			}
		}
		return cntUpwards + upwardStarts[u];
	}

	private void solve() throws NumberFormatException, IOException {
		n = in.nextInt();
		{
			int[] from = new int[n];
			int[] to = new int[n];
			int[] cnt = new int[n];
			for (int i = 0; i < n - 1; i++) {
				from[i] = in.nextInt() - 1;
				to[i] = in.nextInt() - 1;
				cnt[from[i]]++;
				cnt[to[i]]++;
			}
			adj = new int[n][];
			adjIdx = new int[n][];
			for (int i = 0; i < n; i++) {
				adj[i] = new int[cnt[i]];
				adjIdx[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < n - 1; i++) {
				adj[from[i]][cnt[from[i]]] = to[i];
				adj[to[i]][cnt[to[i]]] = from[i];
				adjIdx[from[i]][cnt[from[i]]++] = i;
				adjIdx[to[i]][cnt[to[i]]++] = i;
			}

			int k = in.nextInt();
			int a[] = new int[k];
			int b[] = new int[k];
			Arrays.fill(cnt, 0);
			for (int i = 0; i < k; i++) {
				a[i] = in.nextInt() - 1;
				b[i] = in.nextInt() - 1;
				cnt[a[i]]++;
				cnt[b[i]]++;
			}
			pair = new int[n][];
			for (int i = 0; i < n; i++) {
				pair[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < k; i++) {
				pair[a[i]][cnt[a[i]]++] = b[i];
				pair[b[i]][cnt[b[i]]++] = a[i];
			}
		}
		dsu = new DSU(n);
		vis = new boolean[n];
		lca = new int[n];
		for (int i = 0; i < n; i++) {
			lca[i] = i;
		}
		upwardStarts = new int[n];
		res = new int[n - 1];
		dfs(0, - 1);
		Arrays.fill(vis, false);
		resDfs(0, -1);
		for (int i : res) {
			out.print(i + " ");
		}
	}

	FastScanner in;
	PrintWriter out;

	class FastScanner {
		BufferedReader in;
		StringTokenizer st;

		public FastScanner(Reader reader) {
			in = new BufferedReader(reader);
		}

		private boolean hasNext() throws IOException {
			while (st == null || !st.hasMoreTokens()) {
				String line = in.readLine();
				if (line == null)
					return false;
				st = new StringTokenizer(line);
			}
			return true;
		}

		private String next() throws IOException {
			if (!hasNext()) {
				return null;
			} else {
				return st.nextToken();
			}
		}

		private int nextInt() throws NumberFormatException, IOException {
			return Integer.parseInt(next());
		}
	}

	public static void main(String[] args) {
		new C().run();
	}

	@Override
	public void run() {
		try {
			in = new FastScanner(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			out.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;
import java.util.TreeMap;

public class C implements Runnable {

	static class DSU {
		int p[];
		int r[];

		public DSU(int n) {
			p = new int[n];
			r = new int[n];
			for (int i = 0; i < n; i++) {
				p[i] = i;
				r[i] = 0;
			}
		}

		int get(int u) {
			return p[u] == u ? u : (p[u] = get(p[u]));
		}

		void unite(int u, int v) {
			u = get(u);
			v = get(v);
			if (r[u] > r[v]) {
				p[v] = u;
			} else if (r[v] > r[u]) {
				p[u] = v;
			} else {
				r[u]++;
				p[v] = u;
			}
		}

		boolean same(int u, int v) {
			return get(u) == get(v);
		}
	};

	static class Walk {
		public int from;
		public int to;
		Walk (int from, int to) {
			this.from = from;
			this.to = to;
		}
	}
	int adj[][];
	int lca[];
	int adjIdx[][];
	int pair[][];
	boolean vis[];
	int upwardStarts[];
	int res[];
	DSU dsu;
	int n;

	void dfs(int u, int p) {
		vis[u] = true;
		for (int s : pair[u]) {
			if (s == u || !vis[s])
				continue;
			upwardStarts[dsu.get(s)] -= 2;
			upwardStarts[s]++;
			upwardStarts[u]++;
		}
		for (int v : adj[u]) {
			if (v != p) {
				dfs(v, u);
				dsu.unite(u, v);
				lca[dsu.get(u)] = u;
			}
		}
	}

	int resDfs(int u, int p) {
		vis[u] = true;
		int cntUpwards = 0;
		for (int vi = 0; vi < adj[u].length; vi++) {
			int v = adj[u][vi];
			if (v != p) {
				int upwards = resDfs(v, u);
				res[adjIdx[u][vi]] += upwards;
				cntUpwards += upwards;
			}
		}
		return cntUpwards + upwardStarts[u];
	}

	private void solve() throws NumberFormatException, IOException {
		n = in.nextInt();
		{
			int[] from = new int[n];
			int[] to = new int[n];
			int[] cnt = new int[n];
			for (int i = 0; i < n - 1; i++) {
				from[i] = in.nextInt() - 1;
				to[i] = in.nextInt() - 1;
				cnt[from[i]]++;
				cnt[to[i]]++;
			}
			adj = new int[n][];
			adjIdx = new int[n][];
			for (int i = 0; i < n; i++) {
				adj[i] = new int[cnt[i]];
				adjIdx[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < n - 1; i++) {
				adj[from[i]][cnt[from[i]]] = to[i];
				adj[to[i]][cnt[to[i]]] = from[i];
				adjIdx[from[i]][cnt[from[i]]++] = i;
				adjIdx[to[i]][cnt[to[i]]++] = i;
			}

			int k = in.nextInt();
			int a[] = new int[k];
			int b[] = new int[k];
			Arrays.fill(cnt, 0);
			for (int i = 0; i < k; i++) {
				a[i] = in.nextInt() - 1;
				b[i] = in.nextInt() - 1;
				cnt[a[i]]++;
				cnt[b[i]]++;
			}
			pair = new int[n][];
			for (int i = 0; i < n; i++) {
				pair[i] = new int[cnt[i]];
				cnt[i] = 0;
			}
			for (int i = 0; i < k; i++) {
				pair[a[i]][cnt[a[i]]++] = b[i];
				pair[b[i]][cnt[b[i]]++] = a[i];
			}
		}
		dsu = new DSU(n);
		vis = new boolean[n];
		lca = new int[n];
		upwardStarts = new int[n];
		res = new int[n - 1];
		dfs(0, - 1);
		Arrays.fill(vis, false);
		resDfs(0, -1);
		for (int i : res) {
			out.print(i + " ");
		}
	}

	FastScanner in;
	PrintWriter out;

	class FastScanner {
		BufferedReader in;
		StringTokenizer st;

		public FastScanner(Reader reader) {
			in = new BufferedReader(reader);
		}

		private boolean hasNext() throws IOException {
			while (st == null || !st.hasMoreTokens()) {
				String line = in.readLine();
				if (line == null)
					return false;
				st = new StringTokenizer(line);
			}
			return true;
		}

		private String next() throws IOException {
			if (!hasNext()) {
				return null;
			} else {
				return st.nextToken();
			}
		}

		private int nextInt() throws NumberFormatException, IOException {
			return Integer.parseInt(next());
		}
	}

	public static void main(String[] args) {
		new C().run();
	}

	@Override
	public void run() {
		try {
			in = new FastScanner(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			out.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (NumberFormatException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.StringTokenizer;

public class Main {
	private static final String TASKNAME = "c";

	static class Edge {
		int a, b, id;

		public Edge(int a, int b, int id) {
			super();
			this.a = a;
			this.b = b;
			this.id = id;
		}

	}

	private void solve() throws Exception {
		int n = nextInt();
		ArrayList<Edge>[] g = new ArrayList[n];
		for (int i = 0; i < n; ++i) {
			g[i] = new ArrayList<Main.Edge>();
		}
		for (int i = 0; i < n - 1; ++i) {
			Edge edge = new Edge(nextInt() - 1, nextInt() - 1, i);
			g[edge.a].add(edge);
			g[edge.b].add(edge);
		}

		int[] depth = new int[n];
		int[][] parent = new int[17][n];
		int[] parentEdge = new int[n];
		int[] fools = new int[n];

		Arrays.fill(parent[0], -1);
		hang(0, -1, -1, g, parent, parentEdge, 0, depth);

		for (int i = 1; i < parent.length; ++i) {
			for (int v = 0; v < n; ++v) {
				int p = parent[i - 1][v];
				if (p != -1) {
					p = parent[i - 1][p];
				}
				parent[i][v] = p;
			}
		}

		int pairs = nextInt();
		for (int i = 0; i < pairs; ++i) {
			int a = nextInt() - 1;
			int b = nextInt() - 1;
			if (a == b) {
				continue;
			}

			if (depth[a] > depth[b]) {
				int t = a;
				a = b;
				b = t;
			}

			int c = a;
			int d = b;

			while (depth[d] > depth[c]) {
				for (int j = parent.length - 1; j >= 0; --j) {
					while (true) {
						int p = parent[j][d];
						if (p < 0 || depth[p] < depth[c]) {
							break;
						}
						d = p;
					}
				}
			}
			if (depth[d] != depth[c]) {
				throw new AssertionError();
			}

			for (int j = parent.length - 1; j >= 0; --j) {
				while (true) {
					int p = parent[j][d];
					if (p < 0 || parent[j][c] == p) {
						break;
					}
					d = p;
					c = parent[j][c];
				}
			}
//			System.err.println(c + " " + d);
			if (parent[0][c] != parent[0][d]) {
				throw new AssertionError();
			}

			int lca = (c == d ? c : parent[0][d]);
//			System.err.println("lca of " + a + " " + b + " = " + lca);
			if (lca == a) {
				--fools[a];
				++fools[b];
			} else {
				++fools[a];
				++fools[b];
				fools[lca] -= 2;
			}
		}

//		System.err.println(Arrays.toString(fools));

		int[] ans = new int[n - 1];

		dfs(0, -1, g, fools, ans, parentEdge);

		for (int i : ans) {
			print(i + " ");
		}
		println("");
	}

	private int dfs(int v, int par, ArrayList<Edge>[] g, int[] fools,
			int[] ans, int[] parentEdge) {
		int amount = fools[v];
		for (Edge edge : g[v]) {
			int u = edge.a == v ? edge.b : edge.a;
			if (u == par) {
				continue;
			}
			amount += dfs(u, v, g, fools, ans, parentEdge);
		}
		if (v != 0) {
			ans[parentEdge[v]] = amount;
		}
		return amount;
	}

	private void hang(int v, int par, int parEdge, ArrayList<Edge>[] g,
			int[][] parent, int[] parentEdge, int dep, int[] depth) {
		parent[0][v] = par;
		parentEdge[v] = parEdge;
		depth[v] = dep;
		for (Edge edge : g[v]) {
			int u = edge.a == v ? edge.b : edge.a;
			if (u == par) {
				continue;
			}
			hang(u, v, edge.id, g, parent, parentEdge, dep + 1, depth);
		}
	}

	private void run() {
		try {
			reader = new BufferedReader(new InputStreamReader(System.in));
			writer = new PrintWriter(new OutputStreamWriter(System.out));
//			reader = new BufferedReader(new FileReader(TASKNAME + ".in"));
//			writer = new PrintWriter(new File(TASKNAME + ".out"));

			solve();

			reader.close();
			writer.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(13);
		}
	}

	public static void main(String[] args) {
		long time = System.currentTimeMillis();
		Locale.setDefault(Locale.US);
		new Main().run();
		System.err.printf("%.3f\n", (System.currentTimeMillis() - time) * 1e-3);
	}

	private StringTokenizer tokenizer;
	private PrintWriter writer;
	private BufferedReader reader;

	private String nextToken() throws IOException {
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}

	private int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	private long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	private double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

	private void print(Object o) {
		writer.print(o);
	}

	private void println(Object o) {
		writer.println(o);
	}

	private void printf(String format, Object... args) {
		writer.printf(format, args);
	}
}


import java.util.*;
public class b {
public static void main(String[] args) throws IOException
{
    boolean[] sieve = new boolean[1000001];
    Arrays.fill(sieve, true);
    sieve[0]=sieve[1]=false;
    for(int i = 2; i<sieve.length; i++) if(sieve[i]) for(long j = (long)i*i; j<sieve.length; j+=i) sieve[(int)j] = false;
    //Scanner input = new Scanner(new File("input.txt"));
    //PrintWriter out = new PrintWriter(new File("output.txt"));
    PrintWriter out = new PrintWriter(System.out);
    input.init(System.in);
    int n= input.nextInt();
    int[] st = new int[n], en = new int[n];
    ArrayList<Integer>[] adj = new ArrayList[n];
    for(int i = 0; i<n; i++)adj[i] = new ArrayList<Integer>();
    for(int i = 0; i<n-1; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        st[i] = a;
        en[i] = b;
        adj[a].add(b);
        adj[b].add(a);
    }
    int[] parents = new int[n];
    Arrays.fill(parents,-1);
    parents[0]=-2;
    Queue<Integer> q = new LinkedList<Integer>();
    q.add(0);
    while(!q.isEmpty())
    {
        int at = q.poll();
        for(int i: adj[at])
        {
            if(parents[i]==-1)
            {
                parents[i] = at;
                q.add(i);
            }
        }
    }
    LCT lct = new LCT(n);
    for(int i = 1; i<n; i++)
        lct.link(i,parents[i]);
    int k = input.nextInt();
    for(int i = 0; i<k; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        lct.incToLCA(a, b, 1);
    }
    for(int i = 0; i<n-1; i++)
    {
        int x = (parents[st[i]] == en[i] ? st[i] : en[i]);
        //out.println("X " + x);
        out.print(lct.val(x)+" ");
    }
    out.close();
}
public static long gcd(long a, long b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
static class LCT
{
    int[] parent, left, right, parentpointer, value, prop;
    int NULL;
    LCT(int n)
    {
        value = new int[n+1];   //the value contained in each node
        prop = new int[n+1];    //lazily propagating value change
        Arrays.fill(parent=new int[n+1],NULL=n); //make NULL n to avoid array out of bounds errors
        Arrays.fill(left=new int[n+1],NULL); //parent, left, and right refer to aux tree
        Arrays.fill(right=new int[n+1],NULL);
        Arrays.fill(parentpointer=new int[n+1], NULL); //the root of each aux tree has one of these to that preferred path's top member's parent in represented tree
    }
    //increment everything on the simple path from v to w (going through their LCA)
    void incToLCA(int v, int w, int inc)
    {
        incPath(v, inc);
        incPath(w, inc);
        int lca = LCA(v,w);
        incPath(lca,-2*inc);
        //value[lca] += inc; //if you want to include the LCA in your incrementing
    }
    //returns the least common ancestor of two nodes in the represented tree
    int LCA(int v, int w)
    {
        access(v);
        access(w);
        splay(v);
        if(parentpointer[v] == NULL) return v; //they're in the same aux tree, so w's path to the root passed through v -> answer is v
        return parentpointer[v]; //the point at which the w-root path made the v-root path no longer preferred is where the two paths intersect, or pp[v]
    }
    //finds and splays root of v's represented tree
    int findRoot(int v)
    {
        access(v);
        while(left[v] != NULL) v = left[v];
        splay(v);
        return v;
    }
    //return value at v
    int val(int v)
    {
        access(v);
        return value[v];
    }
    //increment each node on v-root path by inc
    void incPath(int v, int inc)
    {
        access(v);
        value[v] += inc;
        prop[left[v]] += inc;
    }
    //w becomes v's parent
    //must be in different aux trees
    void link(int v, int w)
    {
        access(v);
        access(w);
        parent[left[v]=w] = v;
    }
    //cuts off v from its parent
    void cut(int v)
    {
        access(v);
        parent[left[v]] = NULL;
        left[v] = NULL;
    }
    void access(int v)
    {
        splay(v);
        //get rid of v's preferred child
        if(right[v] != NULL)
        {
            parentpointer[right[v]] = v;
            parent[right[v]] = NULL;
            right[v] = NULL;
        }
        //make v-root path preferred
        while(parentpointer[v] != NULL)
        {
            int w = parentpointer[v];
            splay(w);
            if(right[w]!=NULL)
            {
                parentpointer[right[w]] = w;
            }
            parent[right[w]] = NULL;
            right[w] = v;
            parent[v] = w;
            parentpointer[v] = NULL;
            lift(v);
        }
    }
    //splays vertex v (moves it to top of its aux tree)
    void splay(int v)
    {
        while(parent[v] != NULL)
            if(parent[parent[v]] != NULL && (left[left[parent[parent[v]]]] == v || right[right[parent[parent[v]]]] == v))
                lift(parent[v]);
            else
                lift(v);
    }
    //lift x by one in its aux tree
    void lift(int x)
    {
        //take care of carry
        int inc = prop[parent[x]];
        value[parent[x]] += inc;
        prop[left[parent[x]]] += inc;
        prop[right[parent[x]]] += inc;
        prop[parent[x]] = 0;
        value[x] += prop[x];
        prop[left[x]] += prop[x];
        prop[right[x]] += prop[x];
        prop[x] = 0;
        if(parent[x] == NULL) return;
        parentpointer[x] = parentpointer[parent[x]]; //move parent pointer to x if y is root
        parentpointer[parent[x]] = NULL;
        int y = parent[x], z = parent[y];
        parent[x] = z;
        parent[y] = x;
        if(z != NULL) //adjust grandparent's left/right pointer to point to x
        {
            if(left[z] == y) left[z] = x;
            else right[z] = x;
        }
        if(left[y] == x) //zig (x<p[x])
        {
            left[y] = right[x];
            if(right[x]!=NULL)
                parent[right[x]] = y;
            right[x] = y;
        }
        else //zag (x>p[x])
        {
            right[y] = left[x];
            if(left[x]!=NULL)
                parent[left[x]] = y;
            left[x] = y;
        }
    }
}
public static class input {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /** call this method to initialize reader for InputStream */
    static void init(InputStream input) {
        reader = new BufferedReader(
                     new InputStreamReader(input) );
        tokenizer = new StringTokenizer("");
    }

    /** get next word */
    static String next() throws IOException {
        while ( ! tokenizer.hasMoreTokens() ) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                   reader.readLine() );
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt( next() );
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble( next() );
    }
    static long nextLong() throws IOException {
        return Long.parseLong( next() );
    }
}
}


import java.util.*;
public class b {
public static void main(String[] args) throws IOException
{
    boolean[] sieve = new boolean[1000001];
    Arrays.fill(sieve, true);
    sieve[0]=sieve[1]=false;
    for(int i = 2; i<sieve.length; i++) if(sieve[i]) for(long j = (long)i*i; j<sieve.length; j+=i) sieve[(int)j] = false;
    //Scanner input = new Scanner(new File("input.txt"));
    //PrintWriter out = new PrintWriter(new File("output.txt"));
    PrintWriter out = new PrintWriter(System.out);
    input.init(System.in);
    int n= input.nextInt();
    int[] st = new int[n], en = new int[n];
    ArrayList<Integer>[] adj = new ArrayList[n];
    for(int i = 0; i<n; i++)adj[i] = new ArrayList<Integer>();
    for(int i = 0; i<n-1; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        st[i] = a;
        en[i] = b;
        adj[a].add(b);
        adj[b].add(a);
    }
    int[] parents = new int[n];
    Arrays.fill(parents,-1);
    parents[0]=-2;
    Queue<Integer> q = new LinkedList<Integer>();
    q.add(0);
    while(!q.isEmpty())
    {
        int at = q.poll();
        for(int i: adj[at])
        {
            if(parents[i]==-1)
            {
                parents[i] = at;
                q.add(i);
            }
        }
    }
    LCT lct = new LCT(n);
    for(int i = 1; i<n; i++)
        lct.link(i,parents[i]);
    int k = input.nextInt();
    for(int i = 0; i<k; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        lct.incToLCA(a, b, 1);
    }
    for(int i = 0; i<n-1; i++)
    {
        int x = (parents[st[i]] == en[i] ? st[i] : en[i]);
        //out.println("X " + x);
        out.print(lct.val(x)+" ");
    }
    out.close();
}
public static long gcd(long a, long b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
public static class LCT
{
    int[] parent, left, right, parentpointer, value, prop;
    int NULL;
    LCT(int n)
    {
        value = new int[n+1];   //the value contained in each node
        prop = new int[n+1];    //lazily propagating value change
        Arrays.fill(parent=new int[n+1],NULL=n); //make NULL n to avoid array out of bounds errors
        Arrays.fill(left=new int[n+1],NULL); //parent, left, and right refer to aux tree
        Arrays.fill(right=new int[n+1],NULL);
        Arrays.fill(parentpointer=new int[n+1], NULL); //the root of each aux tree has one of these to that preferred path's top member's parent in represented tree
    }
    //increment everything on the simple path from v to w (going through their LCA)
    void incToLCA(int v, int w, int inc)
    {
        incPath(v, inc);
        incPath(w, inc);
        int lca = LCA(v,w);
        incPath(lca,-2*inc);
        //value[lca] += inc; //if you want to include the LCA in your incrementing
    }
    //returns the least common ancestor of two nodes in the represented tree
    int LCA(int v, int w)
    {
        access(v);
        access(w);
        splay(v);
        if(parentpointer[v] == NULL) return v; //they're in the same aux tree, so w's path to the root passed through v -> answer is v
        return parentpointer[v]; //the point at which the w-root path made the v-root path no longer preferred is where the two paths intersect, or pp[v]
    }
    //finds and splays root of v's represented tree
    int findRoot(int v)
    {
        access(v);
        while(left[v] != NULL) v = left[v];
        splay(v);
        return v;
    }
    //return value at v
    int val(int v)
    {
        access(v);
        return value[v];
    }
    //increment each node on v-root path by inc
    void incPath(int v, int inc)
    {
        access(v);
        value[v] += inc;
        prop[left[v]] += inc;
    }
    //w becomes v's parent
    //must be in different aux trees
    void link(int v, int w)
    {
        access(v);
        access(w);
        parent[left[v]=w] = v;
    }
    //cuts off v from its parent
    void cut(int v)
    {
        access(v);
        parent[left[v]] = NULL;
        left[v] = NULL;
    }
    void access(int v)
    {
        splay(v);
        //get rid of v's preferred child
        if(right[v] != NULL)
        {
            parentpointer[right[v]] = v;
            parent[right[v]] = NULL;
            right[v] = NULL;
        }
        //make v-root path preferred
        while(parentpointer[v] != NULL)
        {
            int w = parentpointer[v];
            splay(w);
            if(right[w]!=NULL)
            {
                parentpointer[right[w]] = w;
            }
            parent[right[w]] = NULL;
            right[w] = v;
            parent[v] = w;
            parentpointer[v] = NULL;
            lift(v);
        }
    }
    //splays vertex v (moves it to top of its aux tree)
    void splay(int v)
    {
        while(parent[v] != NULL)
            if(parent[parent[v]] != NULL && (left[left[parent[parent[v]]]] == v || right[right[parent[parent[v]]]] == v))
                lift(parent[v]);
            else
                lift(v);
    }
    //lift x by one in its aux tree
    void lift(int x)
    {
        //take care of carry
        int inc = prop[parent[x]];
        value[parent[x]] += inc;
        prop[left[parent[x]]] += inc;
        prop[right[parent[x]]] += inc;
        prop[parent[x]] = 0;
        value[x] += prop[x];
        prop[left[x]] += prop[x];
        prop[right[x]] += prop[x];
        prop[x] = 0;
        if(parent[x] == NULL) return;
        parentpointer[x] = parentpointer[parent[x]]; //move parent pointer to x if y is root
        parentpointer[parent[x]] = NULL;
        int y = parent[x], z = parent[y];
        parent[x] = z;
        parent[y] = x;
        if(z != NULL) //adjust grandparent's left/right pointer to point to x
        {
            if(left[z] == y) left[z] = x;
            else right[z] = x;
        }
        if(left[y] == x) //zig (x<p[x])
        {
            left[y] = right[x];
            if(right[x]!=NULL)
                parent[right[x]] = y;
            right[x] = y;
        }
        else //zag (x>p[x])
        {
            right[y] = left[x];
            if(left[x]!=NULL)
                parent[left[x]] = y;
            left[x] = y;
        }
    }
}
public static class input {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /** call this method to initialize reader for InputStream */
    static void init(InputStream input) {
        reader = new BufferedReader(
                     new InputStreamReader(input) );
        tokenizer = new StringTokenizer("");
    }

    /** get next word */
    static String next() throws IOException {
        while ( ! tokenizer.hasMoreTokens() ) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                   reader.readLine() );
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt( next() );
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble( next() );
    }
    static long nextLong() throws IOException {
        return Long.parseLong( next() );
    }
}
}


import java.util.*;
import java.io.*;
public class b {
public static void main(String[] args) throws IOException
{
    boolean[] sieve = new boolean[1000001];
    Arrays.fill(sieve, true);
    sieve[0]=sieve[1]=false;
    for(int i = 2; i<sieve.length; i++) if(sieve[i]) for(long j = (long)i*i; j<sieve.length; j+=i) sieve[(int)j] = false;
    //Scanner input = new Scanner(new File("input.txt"));
    //PrintWriter out = new PrintWriter(new File("output.txt"));
    PrintWriter out = new PrintWriter(System.out);
    input.init(System.in);
    int n= input.nextInt();
    int[] st = new int[n], en = new int[n];
    ArrayList<Integer>[] adj = new ArrayList[n];
    for(int i = 0; i<n; i++)adj[i] = new ArrayList<Integer>();
    for(int i = 0; i<n-1; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        st[i] = a;
        en[i] = b;
        adj[a].add(b);
        adj[b].add(a);
    }
    int[] parents = new int[n];
    Arrays.fill(parents,-1);
    parents[0]=-2;
    Queue<Integer> q = new LinkedList<Integer>();
    q.add(0);
    while(!q.isEmpty())
    {
        int at = q.poll();
        for(int i: adj[at])
        {
            if(parents[i]==-1)
            {
                parents[i] = at;
                q.add(i);
            }
        }
    }
    LCT lct = new LCT(n);
    for(int i = 1; i<n; i++)
        lct.link(i,parents[i]);
    int k = input.nextInt();
    for(int i = 0; i<k; i++)
    {
        int a = input.nextInt()-1, b = input.nextInt()-1;
        lct.incToLCA(a, b, 1);
    }
    for(int i = 0; i<n-1; i++)
    {
        int x = (parents[st[i]] == en[i] ? st[i] : en[i]);
        //out.println("X " + x);
        out.print(lct.val(x)+" ");
    }
    out.close();
}
public static long gcd(long a, long b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
public static class LCT
{
    int[] parent, left, right, parentpointer, value, prop;
    int NULL;
    LCT(int n)
    {
        value = new int[n+1];   //the value contained in each node
        prop = new int[n+1];    //lazily propagating value change
        Arrays.fill(parent=new int[n+1],NULL=n); //make NULL n to avoid array out of bounds errors
        Arrays.fill(left=new int[n+1],NULL); //parent, left, and right refer to aux tree
        Arrays.fill(right=new int[n+1],NULL);
        Arrays.fill(parentpointer=new int[n+1], NULL); //the root of each aux tree has one of these to that preferred path's top member's parent in represented tree
    }
    //increment everything on the simple path from v to w (going through their LCA)
    void incToLCA(int v, int w, int inc)
    {
        incPath(v, inc);
        incPath(w, inc);
        int lca = LCA(v,w);
        incPath(lca,-2*inc);
        //value[lca] += inc; //if you want to include the LCA in your incrementing
    }
    //returns the least common ancestor of two nodes in the represented tree
    int LCA(int v, int w)
    {
        access(v);
        access(w);
        splay(v);
        if(parentpointer[v] == NULL) return v; //they're in the same aux tree, so w's path to the root passed through v -> answer is v
        return parentpointer[v]; //the point at which the w-root path made the v-root path no longer preferred is where the two paths intersect, or pp[v]
    }
    //finds and splays root of v's represented tree
    int findRoot(int v)
    {
        access(v);
        while(left[v] != NULL) v = left[v];
        splay(v);
        return v;
    }
    //return value at v
    int val(int v)
    {
        access(v);
        return value[v];
    }
    //increment each node on v-root path by inc
    void incPath(int v, int inc)
    {
        access(v);
        value[v] += inc;
        prop[left[v]] += inc;
    }
    //w becomes v's parent
    //must be in different aux trees
    void link(int v, int w)
    {
        access(v);
        access(w);
        parent[left[v]=w] = v;
    }
    //cuts off v from its parent
    void cut(int v)
    {
        access(v);
        parent[left[v]] = NULL;
        left[v] = NULL;
    }
    void access(int v)
    {
        splay(v);
        //get rid of v's preferred child
        if(right[v] != NULL)
        {
            parentpointer[right[v]] = v;
            parent[right[v]] = NULL;
            right[v] = NULL;
        }
        //make v-root path preferred
        while(parentpointer[v] != NULL)
        {
            int w = parentpointer[v];
            splay(w);
            if(right[w]!=NULL)
            {
                parentpointer[right[w]] = w;
            }
            parent[right[w]] = NULL;
            right[w] = v;
            parent[v] = w;
            parentpointer[v] = NULL;
            lift(v);
        }
    }
    //splays vertex v (moves it to top of its aux tree)
    void splay(int v)
    {
        while(parent[v] != NULL)
            if(parent[parent[v]] != NULL && (left[left[parent[parent[v]]]] == v || right[right[parent[parent[v]]]] == v))
                lift(parent[v]);
            else
                lift(v);
    }
    //lift x by one in its aux tree
    void lift(int x)
    {
        //take care of carry
        int inc = prop[parent[x]];
        value[parent[x]] += inc;
        prop[left[parent[x]]] += inc;
        prop[right[parent[x]]] += inc;
        prop[parent[x]] = 0;
        value[x] += prop[x];
        prop[left[x]] += prop[x];
        prop[right[x]] += prop[x];
        prop[x] = 0;
        if(parent[x] == NULL) return;
        parentpointer[x] = parentpointer[parent[x]]; //move parent pointer to x if y is root
        parentpointer[parent[x]] = NULL;
        int y = parent[x], z = parent[y];
        parent[x] = z;
        parent[y] = x;
        if(z != NULL) //adjust grandparent's left/right pointer to point to x
        {
            if(left[z] == y) left[z] = x;
            else right[z] = x;
        }
        if(left[y] == x) //zig (x<p[x])
        {
            left[y] = right[x];
            if(right[x]!=NULL)
                parent[right[x]] = y;
            right[x] = y;
        }
        else //zag (x>p[x])
        {
            right[y] = left[x];
            if(left[x]!=NULL)
                parent[left[x]] = y;
            left[x] = y;
        }
    }
}
public static class input {
    static BufferedReader reader;
    static StringTokenizer tokenizer;

    /** call this method to initialize reader for InputStream */
    static void init(InputStream input) {
        reader = new BufferedReader(
                     new InputStreamReader(input) );
        tokenizer = new StringTokenizer("");
    }

    /** get next word */
    static String next() throws IOException {
        while ( ! tokenizer.hasMoreTokens() ) {
            //TODO add check for eof if necessary
            tokenizer = new StringTokenizer(
                   reader.readLine() );
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {
        return Integer.parseInt( next() );
    }

    static double nextDouble() throws IOException {
        return Double.parseDouble( next() );
    }
    static long nextLong() throws IOException {
        return Long.parseLong( next() );
    }
}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

public class C191 {
  static class FastScanner {
    BufferedReader br;
    StringTokenizer st;

    public FastScanner(InputStream in) {
      br = new BufferedReader(new InputStreamReader(in));
      st = new StringTokenizer("");
    }

    public int nextInt() throws IOException {
      if (st.hasMoreTokens()) return Integer.parseInt(st.nextToken());
      st = new StringTokenizer(br.readLine());
      return nextInt();
    }

    public String next() throws IOException {
      if(st.hasMoreTokens()) return st.nextToken();
      st = new StringTokenizer(br.readLine());
      return next();
    }
  }
  public static void main(String[] args) throws IOException {
    FastScanner in = new FastScanner(System.in);
    int n = in.nextInt();
    ArrayList<Integer>[] t = new ArrayList[n];
    for(int i = 0; i < n; i++) t[i] = new ArrayList<Integer>();
    int[] starts = new int[n-1];
    int[] ends = new int[n-1];
    for(int i = 0; i < n-1; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      t[a].add(b);
      t[b].add(a);
      starts[i]=a;
      ends[i]=b;
    }
    Queue<Integer> q = new ArrayDeque<Integer>();
    int[] depth = new int[n];
    Arrays.fill(depth, -1);
    depth[0]=0;
    q.add(0);
    while(!q.isEmpty()) {
      int at = q.poll();
      for(int adj : t[at])
        if(depth[adj]==-1) {
          depth[adj]=depth[at]+1;
          q.add(adj);
        }
    }
    LinkcutTree lct = new LinkcutTree(n);
    for(int i = 0; i < n; i++)
      for(int adj : t[i])
        if(depth[i]<depth[adj])
          lct.link(adj, i);

    int qu = in.nextInt();
    for(int i = 0; i < qu; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      lct.incToLCA(a, b, 1);
    }

    for(int i = 0; i < n-1; i++) {
      if(depth[starts[i]] < depth[ends[i]]) {
        System.out.printf("%d ", lct.valueAt(ends[i]));
      } else {
        System.out.printf("%d ", lct.valueAt(starts[i]));
      }
    }
    System.out.println();
  }
  static class LinkcutTree {
    int[] pp, p, l, r, carry, value;
    int NULL;
    public LinkcutTree(int n) {
      Arrays.fill(p = new int[n + 1], NULL = n);
      Arrays.fill(pp = new int[n + 1], NULL);
      Arrays.fill(l = new int[n + 1], NULL);
      Arrays.fill(r = new int[n + 1], NULL);
      carry = new int[n + 1];
      value = new int[n + 1];
    }
    int valueAt(int v) {
      access(v); push(v);
      return value[v];
    }
    void incToLCA(int v, int w, int x) {
      incPath(v,x); incPath(w,x);
      int lca = lca(v,w);
      incPath(lca,-2*x); // for this problem it is on edges so exclude the LCA...
      // to add LCA add "value[lca]+=x" here
    }
    void incPath(int v, int x) {
      access(v);
      value[v]+=x;
      carry[l[v]]+=x;
    }
    int lca(int v, int w) {
      access(v); access(w); splay(v);
      return pp[v]==NULL?v:pp[v];
    }
    int findRoot(int v) {
      access(v);
      for(; l[v]!=NULL; v=l[v]);
      splay(v);
      return v;
    }
    void cut(int v) {
      access(v);
      p[l[v]]=l[v]=NULL;
    }
    void link(int v, int w) {
      access(v); access(w);
      l[p[w]=v]=w;
    }
    void push(int v) {
      if(carry[v]!=0) {
        value[v]+=carry[v];
        carry[l[v]]+=carry[v];
        carry[r[v]]+=carry[v];
        carry[v]=0;
      }
    }
    void access(int v) {
      splay(v);
      if(r[v]!=NULL) {p[r[v]]=NULL; pp[r[v]]=v;}
      r[v]=NULL;
      for(int w=pp[v]; pp[v]!=NULL; w=pp[v]) {
        splay(w);
        if(r[w]!=NULL) pp[r[w]]=w;
        p[r[w]]=NULL;
        r[w]=v; p[v]=w; pp[v]=NULL;
        lift(v); // equivalent to splay here...
      }
    }
    void splay(int v) {
      for(; p[v]!=NULL; lift(v))
        if(l[l[p[p[v]]]]==v || r[r[p[p[v]]]]==v) lift(p[v]);
        else lift(v);
    }
    void lift(int v) {
      push(p[v]);
      push(v);
      if (p[v] == NULL) return;
      pp[v]=pp[p[v]];
      pp[p[v]]=NULL;
      int[] m=l, a=r;
      if(r[p[v]]==v) {m=r;a=l;}
      m[p[v]]=a[v];
      p[a[v]]=p[v];
      a[v]=p[v];
      p[v]=p[p[v]];
      p[a[v]]=v;
      if(p[v]!=NULL)
        if(l[p[v]]==a[v]) l[p[v]]=v;
        else r[p[v]]=v;
    }
  }
}
/*

5
3 4
4 5
1 4
2 4
3
2 3
1 3
3 5

*/


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

public class C191 {
  static class FastScanner {
    BufferedReader br;
    StringTokenizer st;

    public FastScanner(InputStream in) {
      br = new BufferedReader(new InputStreamReader(in));
      st = new StringTokenizer("");
    }

    public int nextInt() throws IOException {
      if (st.hasMoreTokens()) return Integer.parseInt(st.nextToken());
      st = new StringTokenizer(br.readLine());
      return nextInt();
    }

    public String next() throws IOException {
      if(st.hasMoreTokens()) return st.nextToken();
      st = new StringTokenizer(br.readLine());
      return next();
    }
  }
  public static void main(String[] args) throws IOException {
    FastScanner in = new FastScanner(System.in);
    int n = in.nextInt();
    ArrayList<Integer>[] t = new ArrayList[n];
    for(int i = 0; i < n; i++) t[i] = new ArrayList<Integer>();
    int[] starts = new int[n-1];
    int[] ends = new int[n-1];
    for(int i = 0; i < n-1; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      t[a].add(b);
      t[b].add(a);
      starts[i]=a;
      ends[i]=b;
    }
    Queue<Integer> q = new ArrayDeque<Integer>();
    int[] depth = new int[n];
    Arrays.fill(depth, -1);
    depth[0]=0;
    q.add(0);
    while(!q.isEmpty()) {
      int at = q.poll();
      for(int adj : t[at])
        if(depth[adj]==-1) {
          depth[adj]=depth[at]+1;
          q.add(adj);
        }
    }
    LinkcutTree lct = new LinkcutTree(n);
    for(int i = 0; i < n; i++)
      for(int adj : t[i])
        if(depth[i]<depth[adj])
          lct.link(adj, i);

    int qu = in.nextInt();
    for(int i = 0; i < qu; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      lct.incToLCA(a, b, 1);
    }

    for(int i = 0; i < n-1; i++) {
      if(depth[starts[i]] < depth[ends[i]]) {
        System.out.printf("%d ", lct.valueAt(ends[i]));
      } else {
        System.out.printf("%d ", lct.valueAt(starts[i]));
      }
    }
    System.out.println();
  }
  static class LinkcutTree {
    int[] pp, p, l, r, carry, value;
    int NULL;
    public LinkcutTree(int n) {
      Arrays.fill(p = new int[n + 1], NULL = n);
      Arrays.fill(pp = new int[n + 1], NULL);
      Arrays.fill(l = new int[n + 1], NULL);
      Arrays.fill(r = new int[n + 1], NULL);
      carry = new int[n + 1];
      value = new int[n + 1];
    }
    int valueAt(int v) {
      access(v); push(v);
      return value[v];
    }
    void incToLCA(int v, int w, int x) {
      incPath(v,x); incPath(w,x);
      int lca = lca(v,w);
      incPath(lca,-2*x); // for this problem it is on edges so exclude the LCA...
    }
    void incPath(int v, int x) {
      access(v);
      value[v]+=x;
      carry[l[v]]+=x;
    }
    int lca(int v, int w) {
      access(v); access(w); splay(v);
      return pp[v]==NULL?v:pp[v];
    }
    int findRoot(int v) {
      access(v);
      for(; l[v]!=NULL; v=l[v]);
      splay(v);
      return v;
    }
    void cut(int v) {
      access(v);
      p[l[v]]=l[v]=NULL;
    }
    void link(int v, int w) {
      access(v); access(w);
      l[p[w]=v]=w;
    }
    void push(int v) {
      value[v]+=carry[v];
      carry[l[v]]+=carry[v];
      carry[r[v]]+=carry[v];
      carry[v]=0;
    }
    void access(int v) {
      splay(v);
      push(v);
      if(r[v]!=NULL) {p[r[v]]=NULL; pp[r[v]]=v;}
      r[v]=NULL;
      for(int w=pp[v]; pp[v]!=NULL; w=pp[v]) {
        splay(w);
        push(w);
        if(r[w]!=NULL) pp[r[w]]=w;
        p[r[w]]=NULL;
        r[w]=v; p[v]=w; pp[v]=NULL;
        lift(v); // equivalent to splay here...
      }
    }
    void splay(int v) {
      for(; p[v]!=NULL; lift(v))
        if(l[l[p[p[v]]]]==v || r[r[p[p[v]]]]==v) lift(p[v]);
        else lift(v);
    }
    void lift(int v) {
      push(p[v]);
      push(v);
      if (p[v] == NULL) return;
      pp[v]=pp[p[v]];
      pp[p[v]]=NULL;
      int[] m=l, a=r;
      if(r[p[v]]==v) {m=r;a=l;}
      m[p[v]]=a[v];
      p[a[v]]=p[v];
      a[v]=p[v];
      p[v]=p[p[v]];
      p[a[v]]=v;
      if(p[v]!=NULL)
        if(l[p[v]]==a[v]) l[p[v]]=v;
        else r[p[v]]=v;
    }
  }
}
/*

5
3 4
4 5
1 4
2 4
3
2 3
1 3
3 5

*/


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Queue;
import java.util.StringTokenizer;

public class C191 {
  static class FastScanner {
    BufferedReader br;
    StringTokenizer st;

    public FastScanner(InputStream in) {
      br = new BufferedReader(new InputStreamReader(in));
      st = new StringTokenizer("");
    }

    public int nextInt() throws IOException {
      if (st.hasMoreTokens()) return Integer.parseInt(st.nextToken());
      st = new StringTokenizer(br.readLine());
      return nextInt();
    }

    public String next() throws IOException {
      if(st.hasMoreTokens()) return st.nextToken();
      st = new StringTokenizer(br.readLine());
      return next();
    }
  }
  public static void main(String[] args) throws IOException {
    FastScanner in = new FastScanner(System.in);
    int n = in.nextInt();
    ArrayList<Integer>[] t = new ArrayList[n];
    for(int i = 0; i < n; i++) t[i] = new ArrayList<Integer>();
    int[] starts = new int[n-1];
    int[] ends = new int[n-1];
    for(int i = 0; i < n-1; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      t[a].add(b);
      t[b].add(a);
      starts[i]=a;
      ends[i]=b;
    }
    Queue<Integer> q = new ArrayDeque<Integer>();
    int[] depth = new int[n];
    Arrays.fill(depth, -1);
    depth[0]=0;
    q.add(0);
    while(!q.isEmpty()) {
      int at = q.poll();
      for(int adj : t[at])
        if(depth[adj]==-1) {
          depth[adj]=depth[at]+1;
          q.add(adj);
        }
    }
    LinkcutTree lct = new LinkcutTree(n);
    for(int i = 0; i < n; i++)
      for(int adj : t[i])
        if(depth[i]<depth[adj])
          lct.link(adj, i);

    int qu = in.nextInt();
    for(int i = 0; i < qu; i++) {
      int a = in.nextInt()-1;
      int b = in.nextInt()-1;
      lct.incToLCA(a, b, 1);
    }

    for(int i = 0; i < n-1; i++) {
      if(depth[starts[i]] < depth[ends[i]]) {
        System.out.printf("%d ", lct.valueAt(ends[i]));
      } else {
        System.out.printf("%d ", lct.valueAt(starts[i]));
      }
    }
    System.out.println();
  }
  static class LinkcutTree {
    int[] pp, p, l, r, carry, value;
    int NULL;
    public LinkcutTree(int n) {
      Arrays.fill(p = new int[n + 1], NULL = n);
      Arrays.fill(pp = new int[n + 1], NULL);
      Arrays.fill(l = new int[n + 1], NULL);
      Arrays.fill(r = new int[n + 1], NULL);
      carry = new int[n + 1];
      value = new int[n + 1];
    }
    int valueAt(int v) {
      access(v);
      return value[v];
    }
    void incToLCA(int v, int w, int x) {
      incPath(v,x); incPath(w,x);
      int lca = lca(v,w);
      incPath(lca,-2*x); // for this problem it is on edges so exclude the LCA...
      // to add LCA add "value[lca]+=x" here
    }
    void incPath(int v, int x) {
      access(v);
      value[v]+=x;
      carry[l[v]]+=x;
    }
    int lca(int v, int w) {
      access(v); access(w); splay(v);
      return pp[v]==NULL?v:pp[v];
    }
    int findRoot(int v) {
      access(v);
      for(; l[v]!=NULL; v=l[v]);
      splay(v);
      return v;
    }
    void cut(int v) {
      access(v);
      p[l[v]]=l[v]=NULL;
    }
    void link(int v, int w) {
      access(v); access(w);
      l[p[w]=v]=w;
    }
    void push(int v) {
      if(v!=NULL && carry[v]!=0) {
        value[v]+=carry[v];
        carry[l[v]]+=carry[v];
        carry[r[v]]+=carry[v];
        carry[v]=0;
      }
    }
    void access(int v) {
      splay(v);
      if(r[v]!=NULL) {p[r[v]]=NULL; pp[r[v]]=v;}
      r[v]=NULL;
      for(int w=pp[v]; pp[v]!=NULL; w=pp[v]) {
        splay(w);
        if(r[w]!=NULL) pp[r[w]]=w;
        p[r[w]]=NULL;
        r[w]=v; p[v]=w; pp[v]=NULL;
        lift(v); // equivalent to splay here...
      }
    }
    void splay(int v) {
      for(; p[v]!=NULL; lift(v))
        if(l[l[p[p[v]]]]==v || r[r[p[p[v]]]]==v) lift(p[v]);
        else lift(v);
    }
    void lift(int v) {
      push(p[v]);
      push(v);
      if (p[v] == NULL) return;
      pp[v]=pp[p[v]];
      pp[p[v]]=NULL;
      int[] m=l, a=r;
      if(r[p[v]]==v) {m=r;a=l;}
      m[p[v]]=a[v];
      p[a[v]]=p[v];
      a[v]=p[v];
      p[v]=p[p[v]];
      p[a[v]]=v;
      if(p[v]!=NULL)
        if(l[p[v]]==a[v]) l[p[v]]=v;
        else r[p[v]]=v;
    }
  }
}
/*

5
3 4
4 5
1 4
2 4
3
2 3
1 3
3 5

*/