'use strict'

const n = +readline();
const edges = Array.from({ length: n - 1 }, () => readline().split(' ').map(i => +i - 1));
const passengers = Array.from({ length: +readline() }, () => readline().split(' ').map(i => +i)).map(([ a, b, score ]) => [ a - 1, b - 1, score ]);

const rootTree = (graph, n) => {
    // Do a DFS to (arbitrarily) root the tree and record depths
    const parent = Array(n).fill(null); parent[0] = Infinity;
    const parentEdge = Array(n).fill(null); parentEdge[0] = Infinity;
    const depth = Array(n).fill(null); depth[0] = 0;
    const stack = [ 0 ];
    while (stack.length) {
        const node = stack.pop();
        Object.keys(graph[node]).forEach((k) => {
            const edgeId = graph[node][k];
            if (parent[k] !== null) return;
            parent[k] = node;
            parentEdge[k] = edgeId;
            depth[k] = depth[node] + 1;
            stack.unshift(k);
        });
    }
    return { parent, parentEdge, depth };
}

const getLCAEdges = (parent, parentEdge, depth, source, dest) => {
    // Find shortest path by walking both nodes up till their LCA
    // Returns the edge ids in arbitrary order!
    let A = source, B = dest;

    // Start them at the same depth first
    let dA = depth[A], dB = depth[B];
    const r = [];
    while (dA > dB) {
        r.push(parentEdge[A]);
        A = parent[A];
        dA -= 1;
    }
    while (dA < dB) {
        r.push(parentEdge[B]);
        B = parent[B];
        dB -= 1;
    }
    // Walk up both paths until find lca
    while (A !== B) {
        r.push(parentEdge[A]);
        A = parent[A];
        r.push(parentEdge[B]);
        B = parent[B];
    }
    return r;
}

const problem = (n, edges, passengers) => {
    const graph = {}

    edges.forEach(([ x, y ], i) => {
        if (!graph[x]) graph[x] = {};
        if (!graph[y]) graph[y] = {};
        graph[x][y] = i;
        graph[y][x] = i;
    })

    const rt = rootTree(graph, n)
    const parent = rt.parent;
    const parentEdge = rt.parentEdge;
    const depth = rt.depth;
    // Sort by score, high to low
    passengers.sort((a, b) => b[2] - a[2]);
    // For each passenger, set any unset edges in their path to their min score
    const scores = Array(n - 1).fill(null);

    for (let i = 0; i < passengers.length; i++) {
        const p = passengers[i];
        const a = p[0];
        const b = p[1];
        const score = p[2];
        let numEdges = 0;
        const lca = getLCAEdges(parent, parentEdge, depth, a, b);
        for (let j = 0; j < lca.length; j++) {
            const edgeId = lca[j];
            if (scores[edgeId] === null) {
                numEdges += 1;
                scores[edgeId] = score;
            } else {
                // Since sorted any existing scores must higher or equal
                // Can't overwrite lower because will lower the previous's min score
                if (scores[edgeId] === score) numEdges += 1
            }
        }
        // Need to set at least one edge
        if (numEdges == 0) return -1;
    }

    return scores.map(i => i || 1).join(' ');
}

print(problem(n, edges, passengers));


'use strict'

const n = +readline();

const edges = Array.from({ length: n - 1 }, () => readline().split(' ').map(i => +i - 1));
const passengers = Array.from({ length: +readline() }, () => readline().split(' ').map(i => +i)).map(([ a, b, score ]) => [ a - 1, b - 1, score ]);

const rootTree = (graph, n) => {
    // Do a DFS to (arbitrarily) root the tree and record depths
    const parent = [ Infinity, ...Array(n-1).fill(null) ];
    const parentEdge = [ Infinity, ...Array(n-1).fill(null) ];
    const depth = [ 0, ...Array(n-1).fill(null) ];
    const stack = [ 0 ];
    while (stack.length) {
        const node = stack.pop();
        Object.entries(graph[node]).forEach(([ k, edgeId ]) => {
            if (parent[k] !== null) return;
            parent[k] = node;
            parentEdge[k] = edgeId;
            depth[k] = depth[node] + 1;
            stack.unshift(k);
        });
    }
    return { parent, parentEdge, depth };
}

const getLCAEdges = (parent, parentEdge, depth, source, dest) => {
    // Find shortest path by walking both nodes up till their LCA
    // Returns the edge ids in arbitrary order!
    let A = source, B = dest;

    // Start them at the same depth first
    let dA = depth[A], dB = depth[B];
    const r = [];
    while (dA > dB) {
        r.push(parentEdge[A]);
        A = parent[A];
        dA -= 1;
    }
    while (dA < dB) {
        r.push(parentEdge[B]);
        B = parent[B];
        dB -= 1;
    }
    // Walk up both paths until find lca
    while (A !== B) {
        r.push(parentEdge[A]);
        A = parent[A];
        r.push(parentEdge[B]);
        B = parent[B];
    }
    return r;
}

const problem = (n, edges, passengers) => {
    const graph = {}

    edges.forEach(([ x, y ], i) => {
        if (!graph[x]) graph[x] = {};
        if (!graph[y]) graph[y] = {};
        graph[x][y] = i;
        graph[y][x] = i;
    })

    const { parent, parentEdge, depth } = rootTree(graph, n)
    // Sort by score, high to low
    passengers.sort((a, b) => b[2] - a[2]);
    // For each passenger, set any unset edges in their path to their min score
    const scores = Array(n - 1).fill(null);

    for (let i = 0; i < passengers.length; i++) {
        const [ a, b, score ] = passengers[i];
        let numEdges = 0;
        const lca = getLCAEdges(parent, parentEdge, depth, a, b);
        for (let j = 0; j < lca.length; j++) {
            const edgeId = lca[j];
            if (scores[edgeId] === null) {
                numEdges += 1;
                scores[edgeId] = score;
            } else {
                // Since sorted any existing scores must higher or equal
                // Can't overwrite lower because will lower the previous's min score
                if (scores[edgeId] === score) numEdges += 1
            }
        }
        // Need to set at least one edge
        if (numEdges == 0) return -1;
    }

    return scores.map(i => i || 1).join(' ');
}

print(problem(n, edges, passengers));


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int i = 1 ; i <= n ; i ++){
            for(int j = L-1 ; j >= 1 ; j --){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
            }
    }

    for(int i = 1 ; i <= n ; i ++){
            for(int j = L-1 ; j >= 1 ; j --){
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N][L] , val[N][L];
int u[N] , v[N] , e[N];

int dep[N];

multiset < int > ms;
vi add[N] , take[N];

vii adj[N];
int node_for_edge[N];

void dfs(int u , int p){
    to[u][0] = p;
    dep[u] = 1 + dep[p];

    for(int i = 1 ; i < L ; i ++)to[u][i] = to[ to[u][i-1] ][i-1];

    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == p)continue;

            node_for_edge[e] = v;
            dfs(v , u);
    }
}

int jump(int u , int k){
    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i))u = to[u][i];
    }
    return u;
}

int LCA(int u , int v){
    if(u == v)return u;

    if(dep[u] < dep[v])swap(u , v);

    u = jump(u , dep[u] - dep[v]);
    if(u == v)return u;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return to[u][0];
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void dfs_process(int u , int p){
    for(int A : add[u])ms.insert(A);
    for(int T : take[p]){
            auto it = ms.find(T);
            if(it != ms.end())ms.erase(it);
    }

    //cout << u << " " << p << endl;
    //cout << "values = " ; for(int M : ms)cout << M << " " ; cout << endl; cout << endl;

    int mx = 1;

    if(!ms.empty()){
            auto it = ms.end(); it --;
            mx = *it;
    }
    val[u][0] = mx;

    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == p)continue;

            dfs_process(v , u);
    }

    for(int A : add[u]){
            auto it = ms.find(A);
            if(it != ms.end())ms.erase(it);
    }
    for(int T : take[p])ms.insert(T);
}

void solve(int testCase){

    scanf("%d" , &n);
    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    scanf("%d" , &m);

    for(int i = 0 ; i < m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);

            int lca = LCA(u[i] , v[i]);

            int addu = jump(u[i] , dep[u[i]] - dep[lca] - 1);
            int addv = jump(v[i] , dep[v[i]] - dep[lca] - 1);

            //cout << "addu = " << addu << " , addv = " << addv << endl;

            add[addu].push_back(e[i]);
            if(addv != addu)add[addv].push_back(e[i]);

            if(v[i] != lca)take[v[i]].push_back(e[i]);
            if(u[i] != lca)take[u[i]].push_back(e[i]);
    }

    /*
    for(int i = 1 ; i <= n ; i ++){
            cout << "curr node = " << i << endl;
            cout << "add: "; for(int A : add [i])cout << A << " "; cout << endl;
            cout << "erase: "; for(int T : take[i])cout << T << " "; cout << endl;
            cout << endl;
    }
    */

    dfs_process(1 , 0);

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 0 ; i < m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 5000 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int Euler = 0;
int E[N << 2 + 1];
int L[N << 2 + 1];
int H[N]; /// first occurrence

int st  [N << 8];
int mn  [N << 8];
int mx  [N << 8];
int lazy[N << 8];
int dep[N];

int u[N] , v[N] , e[N];
int ans[N << 2 + 1];

vii adj[N];
int node_for_edge[N];

int mrg(int a , int b){
    if(a == 1e9)return b;
    if(b == 1e9)return a;

    if(dep[a] < dep[b]) return a;
    return b;
}

void build(int p , int l , int r){
    if(l == r){
            st[p] = E[l];
            return;
    }

    int mid = (l + r) >> 1;

    build(p << 1 , l , mid);
    build(p << 1 | 1 , mid + 1 , r);

    st[p] = mrg(st[p << 1] , st[p << 1 | 1]);
}

int query_lca(int p , int l , int r , int S , int E){
    if(l >= S && r <= E) return st[p];
    if(l > E || r < S) return 1e9;

    int mid = (l + r ) >> 1;

    return mrg(query_lca(p << 1 , l , mid , S , E) , query_lca(p << 1 | 1 , mid + 1 , r , S , E));
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    mx[p] = max(mx[p] , lazy[p]);

    if(l != r){
            lazy[p << 1] = max(lazy[p << 1] , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update(int p , int l , int r , int S , int E , int new_val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , new_val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update(p << 1     , l       , mid , S , E , new_val);
    update(p << 1 | 1 , mid + 1 , r   , S , E , new_val);

    mx[p] = max(mx[p << 1] , mx[p << 1 | 1]);
}

int query_max(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return mx[p];
    if(l > E || r < S)return 0;

    int mid = (l + r) >> 1;

    return max(query_max(p << 1 , l , mid , S , E) , query_max(p << 1 | 1 , mid + 1 , r , S , E));
}

void build_min(int p , int l , int r){
    if(l == r){
            mn[p] = ans[l];
            return;
    }

    int mid = (l + r) >> 1;

    build_min(p << 1 , l , mid);
    build_min(p << 1 | 1 , mid + 1 , r);

    mn[p] = min(mn[p << 1] , mn[p << 1 | 1]);
}

int query_min(int p , int l , int r , int S , int E){
    if(l >= S && r <= E)return mn[p];
    if(l > E || r < S)return 2e9;

    int mid = (l + r) >> 1;

    return min(query_min(p << 1 , l , mid , S , E) , query_min(p << 1 | 1 , mid + 1 , r , S , E));
}

int get_lca(int u , int v){
    int l = H[u] , r = H[v];

    if(l > r)swap(l , r);

    return query_lca(1 , 1 , 2*n - 1 , l , r);
}

void update_path(int u , int lca , int w){
    if(H[u] < H[lca]){
            update(1 , 1 , 2*n - 1 , H[u] , H[lca] - 1 , w);
    }
    else {
            update(1 , 1 , 2*n - 1 , H[lca] + 1 , H[u] , w);
    }
}

void change(int u , int v , int w){
    int lca = get_lca(u , v);

    if(u != lca)update_path(u , lca , w);
    if(v != lca)update_path(v , lca , w);
}

int ask(int u , int lca){

    //cout << "u = " << u << " , lca = " << lca << endl;
    //cout << H[u] << " " << H[lca] << endl;
    if(H[u] < H[lca]){
            return query_min(1 , 1 , 2*n - 1 , H[u] , H[lca] - 1);
    }
    else {
            return query_min(1 , 1 , 2*n - 1 , H[lca] + 1 , H[u]);
    }
}

int get_min(int u , int v){
    int lca = get_lca(u , v);

    int ret = 2e9;
    if(u != lca)ret = min(ret , ask(u , lca));
    if(v != lca)ret = min(ret , ask(v , lca));

    return ret;
}

void dfs(int u , int p){

    dep[u] = 1 + dep[p];

    Euler ++;
    H[u] = Euler;
    E[Euler] = u;
    L[Euler] = dep[u];

    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == p)continue;

            node_for_edge[e] = v;
            dfs(v , u);

            Euler ++;
            E[Euler] = u;
            L[Euler] = dep[u];
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    int sz = 2 * n - 1;

    build(1 , 1 , sz);

    scanf("%d" , &m);

    for(int i = 1 ; i <= 2*n - 1 ; i ++){
            update(1 , 1 , 2*n - 1 , i , i , 1);
    }
    for(int i = 0 ; i < m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);

            change(u[i] , v[i] , e[i]);
    }

    //cout << endl;
    for(int i = 1 ; i <= 2*n - 1 ; i ++){
            ans[i] = query_max(1 , 1 , 2*n - 1 , i , i);
            //cout << ans[i] << " ";
    }
    //cout << endl;

    build_min(1 , 1 , 2*n - 1);

    /*
    cout << endl;
    for(int i = 1 ; i <= 2*n-1 ; i ++){
            cout << query_min(1 , 1 , 2*n - 1 , i , i) << " ";
    }
    cout << endl;
    */

    for(int i = 0 ; i < m ; i ++){

            //cout << "query: " << u[i] << " " << v[i] << " " << e[i] << endl;
            //cout << "ans: " << get_min(u[i] , v[i]) << endl;
            if(get_min(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            int u = node_for_edge[i];

            printf("%d%c" , ans[H[u]] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p [v] = u;
            dep[v] = 1 + dep[u];

            int curr = dfs(v , u);

            sz += curr;

            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(chain[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1]     , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            int curr = query(u[i] , v[i]);
            if(curr == 2e9){
                    cout << "2e9" << endl;
                    0/0;
            }
            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            assert(segTreePos[to[i]] <= n);
            int curr = rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]);
            if(curr == 2e9)curr = 1;
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs_hld(int u){

    if(u != 1)dep[u] = 1 + dep[p[u]];

    int sz = 1;
    int mx = 0;///heavy child
    for(ii A : adj[u]){
        int v  = A.second;
        int dx = A.first;///edge index

        if(v == p[u])continue;

         p[v]  = u;
        to[dx] = v;///map this edge to node v
        int curr = dfs_hld(v);

        if(curr > mx){
            mx = curr;
            heavy[u] = v;
        }

        sz += curr;
    }

    return sz;
}

void build_chains(){

    dfs_hld(1);

    int pos = 0;///pos in segment tree

    for(int chainRoot = 1 ; chainRoot <= n ; chainRoot ++){

        if(p[ chainRoot ] == -1 || heavy[ p[ chainRoot ] ] != chainRoot){

            for(int j = chainRoot ; j != -1 ; j = heavy[j]){

                chain[j] = chainRoot;
                segTreePos[j] = ++ pos;

            }

        }

    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1]     , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            if(query(u[i],  v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            int curr = rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]);
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    memset(heavy , -1 , sizeof heavy);
    memset(p     , -1 , sizeof p    );

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);

            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher rows to lower rows
    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
            }
    }

    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int i = 1 ; i <= n ; i ++){
            for(int j = L-1 ; j >= 1 ; j --){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    /*
    for(int i = 1 ; i <= n ; i ++){
            for(int j = L-1 ; j >= 1 ; j --){
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    */
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N] , w[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p[v] = u;
            dep[v] = 1 + dep[u];
            int curr = dfs(v , u);
            sz += curr;
            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(chain[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1] , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
            w[i] = 1;
    }

    build_chains();

    for(int i = 0 ; i < N << 2 ; i ++){
            st[i] = 1;
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            int curr = query(u[i] , v[i]);
            if(curr == 2e9)curr = 1;
            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            int curr = rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]);
            if(curr == 2e9)curr = 1;
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N] , w[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p[v] = u;
            dep[v] = 1 + dep[u];
            int curr = dfs(v , u);
            sz += curr;
            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(chain[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1] , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = val;
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
            w[i] = 1;
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            if(query(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]) , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    /*
    for(int i = 1 ; i <= n ; i ++){
            for(int j = L-1 ; j >= 1 ; j --){
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    */
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs_hld(int u){

    if(u != 1)dep[u] = 1 + dep[p[u]];

    int sz = 1;
    int mx = 0;///heavy child
    for(ii A : adj[u]){
        int v  = A.second;
        int dx = A.first;///edge index

        if(v == p[u])continue;

         p[v]  = u;
        to[dx] = v;///map this edge to node v
        int curr = dfs_hld(v);

        if(curr > mx){
            mx = curr;
            heavy[u] = v;
        }

        sz += curr;
    }

    return sz;
}

void build_chains(){

    dfs_hld(1);

    int pos = 0;///pos in segment tree

    for(int chainRoot = 1 ; chainRoot <= n ; chainRoot ++){

        if(chain[ chainRoot ] == -1 || heavy[ p[ chainRoot ] ] != chainRoot){

            for(int j = chainRoot ; j != -1 ; j = heavy[j]){

                chain[j] = chainRoot;
                segTreePos[j] = ++ pos;

            }

        }

    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1]     , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            assert(u <= n);
            assert(v <= n);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            int curr = query(u[i] , v[i]);

            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            if(segTreePos[to[i]] > n){
                    cout << i << " " << to[i] << " " << segTreePos[to[i]] << endl;
                    assert(5 > 6);
            }
            int curr = rmq(1 , 1 , N-1 , segTreePos[to[i]] , segTreePos[to[i]]);
            if(curr == 2e9)curr = 1;
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    memset(heavy , -1 , sizeof heavy);
    memset(chain , -1 , sizeof chain);
    memset(p     , -1 , sizeof p    );

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N] , w[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p[v] = u;
            dep[v] = 1 + dep[u];
            int curr = dfs(v , u);
            sz += curr;
            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(p[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = lazy[p];
            lazy[p << 1 | 1] = lazy[p];
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = val;
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
            w[i] = 1;
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            if(query(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]) , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs_hld(int u){

    if(u != 1)dep[u] = 1 + dep[p[u]];

    int sz = 1;
    int mx = 0;///heavy child
    for(ii A : adj[u]){
        int v  = A.second;
        int dx = A.first;///edge index

        if(v == p[u])continue;

         p[v]  = u;
        to[dx] = v;///map this edge to node v
        int curr = dfs_hld(v);

        if(curr > mx){
            mx = curr;
            heavy[u] = v;
        }

        sz += curr;
    }

    return sz;
}

void build_chains(){

    dfs_hld(1);

    int pos = 0;///pos in segment tree

    for(int chainRoot = 1 ; chainRoot <= n ; chainRoot ++){

        if(p[ chainRoot ] == -1 || heavy[ p[ chainRoot ] ] != chainRoot){

            for(int j = chainRoot ; j != -1 ; j = heavy[j]){

                chain[j] = chainRoot;
                segTreePos[j] = ++ pos;

            }

        }

    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1]     , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , N-1 , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , N-1 , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , N-1 , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , N-1 , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            assert(u <= n);
            assert(v <= n);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    build_chains();

    for(int i = 1 ; i <= n ; i ++){
            if(segTreePos[i] > n){
                cout << "i = " << i << " , pos = " << segTreePos[i] << endl;
                assert(5 > 6);
            }
    }

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , N-1 , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            int curr = query(u[i] , v[i]);

            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            if(segTreePos[to[i]] > n){
                    cout << i << " " << to[i] << " " << segTreePos[to[i]] << endl;
                    assert(5 > 6);
            }
            int curr = rmq(1 , 1 , N-1 , segTreePos[to[i]] , segTreePos[to[i]]);
            if(curr == 2e9)curr = 1;
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    memset(heavy , -1 , sizeof heavy);
    memset(p     , -1 , sizeof p    );

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 3e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p [v] = u;
            dep[v] = 1 + dep[u];

            int curr = dfs(v , u);

            sz += curr;

            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(chain[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = max(lazy[p << 1]     , lazy[p]);
            lazy[p << 1 | 1] = max(lazy[p << 1 | 1] , lazy[p]);
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = max(lazy[p] , val);
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            int curr = query(u[i] , v[i]);

            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            if(segTreePos[to[i]] > n){
                    cout << i << " " << to[i] << " " << segTreePos[to[i]] << endl;
                    assert(5 > 6);
            }
            int curr = rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]);
            if(curr == 2e9)curr = 1;
            printf("%d%c" , curr , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N][L];
int val[N][L];
int dep[N];
int node_of_edge[N];
int u[N] , v[N] , e[N];

vii adj[N];

void dfs(int u , int p){
    to[u][0] = p;
    dep[u] = 1 + dep[p];
    val[u][0] = 1;

    for(int i = 0 ; i < L ; i ++){
            to[u][i] = to[ to[u][i-1] ][i-1];
    }

    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == p)continue;

            node_of_edge[e] = v;
            dfs(v , u);
    }
}

int jump(int u , int k){
    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    u = to[u][i];
            }
    }
    return u;
}

int get_lca(int u , int v){
    if(u == v)return u;

    if(dep[u] < dep[v])swap(u , v);

    u = jump(u , dep[u] - dep[v]);
    if(u == v)return u;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    u = to[u][i];
                    v = to[u][i];
            }
    }

    return to[u][0];
}

void update(int u , int k , int new_val){
    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }
}

int get_min_val(int u , int k){
    int ret = 2e9;

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }
    return ret;
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    scanf("%d" , &m);

    for(int i = 0 ; i < m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);

            int lca = get_lca(u[i] , v[i]);

            update(u[i] , dep[u[i]] - dep[lca] - 1 , e[i]);
            update(v[i] , dep[v[i]] - dep[lca] - 1 , e[i]);
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j] , val[i][j-1]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j] );
            }
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 0 ; i < m ; i ++){
            int lca = get_lca(u[i] , v[i]);
            int curr =            get_min_val(u[i] , dep[u[i]] - dep[lca] - 1);
                curr = min(curr , get_min_val(v[i] , dep[v[i]] - dep[lca] - 1));

            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_of_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N] , p[N] , w[N];
int  u[N] , v[N] , e[N];
int dep[N];

int segTreePos[N] , heavy[N] , chain[N];
int st[N << 2] , lazy[N << 2];

vii adj[N];

int dfs(int u , int pr){

    int sz = 1;
    int mx = 0;
    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == pr)continue;

            to[e] = v;
            p[v] = u;
            dep[v] = 1 + dep[u];
            int curr = dfs(v , u);
            sz += curr;
            if(curr > mx){
                    mx = curr;
                    heavy[u] = v;
            }
    }

    return sz;
}

void build_chains(){
    dfs(1 , 0);

    int pos = 0;

    for(int i = 1 ; i <= n ; i ++){
            if(chain[i] == 0 || heavy[ p[i] ] !=  i){
                    for(int j = i ; j != 0 ; j = heavy[j]){
                            segTreePos[j] = ++ pos;
                            chain[j] = i;
                    }
            }
    }
}

void psh(int p , int l , int r){
    if(lazy[p] == 0)return;

    st[p] = max(st[p] , lazy[p]);

    if(l != r){
            lazy[p << 1]     = lazy[p];
            lazy[p << 1 | 1] = lazy[p];
    }

    lazy[p] = 0;
}

void update_range(int p , int l , int r , int S , int E , int val){
    psh(p , l , r);

    if(l >= S && r <= E){
            lazy[p] = val;
            psh(p , l , r);
            return;
    }
    if(l > E || r < S)return;

    int mid = (l + r) >> 1;

    update_range(p << 1 , l , mid , S , E , val);
    update_range(p << 1 | 1 , mid + 1 , r , S , E , val);

    st[p] = min(st[p << 1] , st[p << 1 | 1]);
}

int rmq(int p , int l , int r , int S , int E){
    psh(p , l , r);

    if(l >= S && r <= E)return st[p];
    if(l > E || r < S)  return 2e9;

    int mid = (l + r) >> 1;

    return min(rmq(p << 1 , l , mid , S , E) , rmq(p << 1 | 1 , mid + 1 , r , S , E));
}

int query(int u , int v){

    int ret = 2e9;
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            ret = min(ret , rmq(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u]));
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            ret = min(ret , rmq(1 , 1 , n , l+1 , r));
    }

    return ret;
}

void update(int u , int v , int val){
    for( ; chain[u] != chain[v] ; u = p[chain[u]]){
            if(dep[ chain[u] ] < dep[ chain[v] ])swap(u , v);

            update_range(1 , 1 , n , segTreePos[ chain[u] ] , segTreePos[u] , val);
    }

    if(u != v){
            int l = segTreePos[u] , r = segTreePos[v];
            if(l > r)swap(l , r);

            update_range(1 , 1 , n , l+1 , r , val);
    }
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
            w[i] = 1;
    }

    build_chains();

    for(int i = 1 ; i < n ; i ++){
            update_range(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]] , 1);
    }

    scanf("%d" , &m);
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update(u[i] , v[i] , e[i]);
    }

    for(int i = 1 ; i <= m ; i ++){
            if(query(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , rmq(1 , 1 , n , segTreePos[to[i]] , segTreePos[to[i]]) , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    //val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    /*
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }
    */
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int to[N][L];
int val[N][L];
int dep[N];
int node_of_edge[N];
int u[N] , v[N] , e[N];

vii adj[N];

void dfs(int u , int p){
    to[u][0] = p;
    dep[u] = 1 + dep[p];
    val[u][0] = 1;

    for(int i = 0 ; i < L ; i ++){
            to[u][i] = to[ to[u][i-1] ][i-1];
    }

    for(ii A : adj[u]){
            int v = A.second;
            int e = A.first;

            if(v == p)continue;

            node_of_edge[e] = v;
            dfs(v , u);
    }
}

int jump(int u , int k){
    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    u = to[u][i];
            }
    }
    return u;
}

int get_lca(int u , int v){
    if(u == v)return u;

    if(dep[u] < dep[v])swap(u , v);

    u = jump(u , dep[u] - dep[v]);
    if(u == v)return u;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    u = to[u][i];
                    v = to[u][i];
            }
    }

    return to[u][0];
}

void update(int u , int k , int new_val){
    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }
}

int get_min_val(int u , int k){
    int ret = 2e9;

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }
    return ret;
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    scanf("%d" , &m);

    for(int i = 0 ; i < m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);

            int lca = get_lca(u[i] , v[i]);

            update(u[i] , dep[u[i]] - dep[lca] , e[i]);
            update(v[i] , dep[v[i]] - dep[lca] , e[i]);
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j] , val[i][j-1]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j] );
            }
    }

    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 0 ; i < m ; i ++){
            int lca = get_lca(u[i] , v[i]);
            int curr =            get_min_val(u[i] , dep[u[i]] - dep[lca]);
                curr = min(curr , get_min_val(v[i] , dep[v[i]] - dep[lca]));

            if(curr != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_of_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}


#include<bits/stdc++.h>

using namespace std;

using ll   = long long;
using ii   = pair   < int , int >;
using i3   = pair   < int , ii  >;
using li   = pair   < ll  , int >;
using lii  = pair   < ll  , ii  >;
using pll  = pair   < ll  , ll  >;
using vi   = vector < int       >;
using vl   = vector < ll        >;
using vii  = vector < ii        >;
using vli  = vector < li        >;
using vpll = vector < pll       >;
using vi3  = vector < i3        >;
using vlii = vector < lii       >;

const int N = 2e5 + 5 , L = 20;
const ll INF = 1e17 + 7;
const double eps = 1e-9 , PI = acos(-1);

int n , m;

int u[N] , v[N] , e[N];
int to[N][L] , val[N][L];
int dep[N];

int node_for_edge[N];

vector < pair < int , int > > adj[N];

void dfs(int u , int p){
    to [u][0] = p;
    val[u][0] = 1;
    dep[u] = 1 + dep[p];

    for(pair < int , int > A : adj[u]){
            int v  = A.second;
            int edge_index = A.first;

            if(v == p)continue;

            node_for_edge[ edge_index ] = v;
            dfs(v , u);
    }
}

/// we try to find the LCA and we do updates on the way
void update_path(int u , int v , int new_val){
    if(u == v)return;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < L ; i ++){
            if(k & (1 << i)){
                    /// update
                    val[u][i] = max(val[u][i] , new_val);
                    u = to[u][i];
            }
    }

    if(u == v)return;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    /// update for u
                    val[u][i] = max(val[u][i] , new_val);
                    /// update for v
                    val[v][i] = max(val[v][i] , new_val);

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    /// update last 2 edges
    val[u][0] = max(val[u][0] , new_val);
    val[v][0] = max(val[v][0] , new_val);
}

int get_min_val(int u , int v){
    if(u == v)return 0;

    int ret = 2e9;

    if(dep[u] < dep[v])swap(u , v);

    int k = dep[u] - dep[v];

    for(int i = 0 ; i < k ; i ++){
            if(k & (1 << i)){
                    ret = min(ret , val[u][i]);
                    u = to[u][i];
            }
    }

    if(u == v)return ret;

    for(int i = L-1 ; i >= 0 ; i --){
            if(to[u][i] != to[v][i]){
                    ret = min({ret , val[u][i] , val[v][i]});

                    u = to[u][i];
                    v = to[v][i];
            }
    }

    return min({ ret , val[u][0] , val[v][0] });
}

void solve(int testCase){

    scanf("%d" , &n);

    for(int i = 1 ; i < n ; i ++){
            int u , v; scanf("%d %d" , &u , &v);

            adj[u].push_back({i , v});
            adj[v].push_back({i , u});
    }

    dfs(1 , 0);

    /// build sparse table
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    to [i][j] =                   to [ to[i][j-1] ][j-1] ;
                    val[i][j] = max(val[i][j-1] , val[ to[i][j-1] ][j-1]);

                    //cout << val[i][j] << " ";
            }
    }
    //cout << endl;

    scanf("%d" , &m);

    /// take the queries and update values on paths
    for(int i = 1 ; i <= m ; i ++){
            scanf("%d %d %d" , &u[i] , &v[i] , &e[i]);
            update_path(u[i] , v[i] , e[i]);
    }

    /// after updates we push values from higher columns to lower columns
    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }

    for(int j = L-1 ; j >= 1 ; j --){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j-1] = max(val[i][j-1] , val[i][j]);
                    val[ to[i][j-1] ][j-1] = max(val[ to[i][j-1] ][j-1] , val[i][j]);
            }
    }
    /// after that all the values of the edges will be in val[i][0];

    /// then we initialize for minimum queries
    for(int j = 1 ; j < L ; j ++){
            for(int i = 1 ; i <= n ; i ++){
                    val[i][j] = min(val[i][j-1] , val[ to[i][j-1] ][j-1]);
            }
    }

    for(int i = 1 ; i <= m ; i ++){
            //cout << u[i] << " " << v[i] << " " << e[i] << " , " << get_min_val(u[i] , v[i]) << endl;
            if(get_min_val(u[i] , v[i]) != e[i]){
                    printf("-1\n");
                    return;
            }
    }

    for(int i = 1 ; i < n ; i ++){
            printf("%d%c" , val[ node_for_edge[i] ][0] , i == n-1 ? '\n' : ' ');
    }

}

main(){

    int t = 1;
    // scanf("%d" , &t);

    for(int testCase = 1 ; testCase <= t ; testCase ++){
            solve(testCase);
    }

    return 0;
}