#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 70000;
const int INFINIT = 2000000000;
int minim[MAXN + 1], maxim[MAXN + 1], match[2 * MAXN + 1], aux, viz[MAXN + 1], answer[MAXN + 1], queries[MAXN + 1];
vector<int> g[MAXN + 1], gnou[MAXN + 1];
struct SegmentTree {
struct Node {
int minim, maxim;
} tree[4 * MAXN];
int n;
void build(int node, int left, int right) {
tree[node] = {0, INFINIT};
if(left < right) {
int middle = (left + right) / 2;
build(2 * node, left, middle);
build(2 * node + 1, middle + 1, right);
}
}
void init(int n) {
this->n = n;
build(1, 1, n);
}
void updateMax(int node, int left, int right, int qleft, int qright, int val) {
if(qleft <= left && right <= qright) {
tree[node].maxim = min(tree[node].maxim, val);
} else {
int middle = (left + right) / 2;
if(qleft <= middle) {
updateMax(2 * node, left, middle, qleft, qright, val);
}
if(middle < qright) {
updateMax(2 * node + 1, middle + 1, right, qleft, qright, val);
}
}
}
void updateMax(int st, int dr, int val) {
updateMax(1, 1, n, st, dr, val);
}
void updateMin(int node, int left, int right, int qleft, int qright, int val) {
if(qleft <= left && right <= qright) {
tree[node].minim = max(tree[node].minim, val);
} else {
int middle = (left + right) / 2;
if(qleft <= middle) {
updateMin(2 * node, left, middle, qleft, qright, val);
}
if(middle < qright) {
updateMin(2 * node + 1, middle + 1, right, qleft, qright, val);
}
}
}
void updateMin(int st, int dr, int val) {
updateMin(1, 1, n, st, dr, val);
}
void dfs(int node, int left, int right, int lazymin, int lazymax) {
lazymin = max(lazymin, tree[node].minim);
lazymax = min(lazymax, tree[node].maxim);
if(left == right) {
minim[left] = lazymin;
maxim[left] = lazymax;
} else {
int middle = (left + right) / 2;
dfs(2 * node, left, middle, lazymin, lazymax);
dfs(2 * node + 1, middle + 1, right, lazymin, lazymax);
}
}
void dfs() {
dfs(1, 1, n, 0, INFINIT);
}
} aint;
struct HeavyLightDecomposition {
int parent[MAXN + 1], depth[MAXN + 1], heavy[MAXN + 1], poz[MAXN + 1], head[MAXN + 1];
int dfs(int node) {
int sz = 1, heavy_size = 0;
for(int son : g[node]) {
if(son != parent[node]) {
parent[son] = node;
depth[son] = 1 + depth[node];
int son_size = dfs(son);
if(son_size > heavy_size) {
heavy_size = son_size;
heavy[node] = son;
}
sz += son_size;
}
}
return sz;
}
void decompose(int node, int start) {
static int timer = 0;
poz[node] = ++timer;
head[node] = start;
if(heavy[node] > 0) {
decompose(heavy[node], start);
for(int son : g[node]) {
if(son != parent[node] && son != heavy[node]) {
decompose(son, son);
}
}
}
}
void init(int n) {
dfs(1);
decompose(1, 1);
aint.init(n);
}
void updateMax(int u, int v, int val) {
while(head[u] != head[v]) {
if(depth[head[u]] < depth[head[v]]) {
swap(u, v);
}
aint.updateMax(poz[head[u]], poz[u], val);
u = parent[head[u]];
}
if(depth[u] > depth[v]) {
swap(u, v);
}
aint.updateMax(poz[u] + 1, poz[v], val);
}
void updateMin(int u, int v, int val) {
while(head[u] != head[v]) {
if(depth[head[u]] < depth[head[v]]) {
swap(u, v);
}
aint.updateMin(poz[head[u]], poz[u], val);
u = parent[head[u]];
}
if(depth[u] > depth[v]) {
swap(u, v);
}
aint.updateMin(poz[u] + 1, poz[v], val);
}
} hld;
bool kuhn(int u) {
viz[u] = aux;
for(int v : g[u]) {
if(match[v] == 0) {
match[u] = v;
match[v] = u;
return true;
}
}
for(int v : g[u]) {
if(viz[match[v]] < aux && kuhn(match[v])) {
match[u] = v;
match[v] = u;
return true;
}
}
return false;
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
hld.init(n);
int q;
cin >> q;
for(int i = 1; i <= q; i++) {
char type;
int u, v, val;
cin >> type >> u >> v >> val;
queries[i] = val;
if(type == 'M') {
hld.updateMax(u, v, val);
} else {
hld.updateMin(u, v, val);
}
}
aint.dfs();
for(int i = 2; i <= n; i++) {
if(minim[hld.poz[i]] > 0) {
gnou[minim[hld.poz[i]]].push_back(q + i);
}
if(maxim[hld.poz[i]] < INFINIT) {
gnou[maxim[hld.poz[i]]].push_back(q + i);
}
}
for(int i = 1; i <= q; i++) {
aux = i;
kuhn(i);
}
for(int i = 1; i <= q; i++) {
answer[match[i] - q] = queries[i];
}
for(int i = 2; i <= n; i++) {
cout << hld.parent[i] << " " << i << " ";
if(answer[i] > 0) {
cout << answer[i] << "\n";
} else if(maxim[hld.poz[i]] < INFINIT) {
cout << maxim[hld.poz[i]] << "\n";
} else {
cout << minim[hld.poz[i]] << "\n";
}
}
return 0;
}