#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m;
struct Edge {
int to, next;
} edge[MAXN * 2];
int start[MAXN], fth[MAXN];
struct LCA {
int x, y, z, val;
} lca[MAXN];
struct Query_LCA {
int to, id;
};
vector<Query_LCA> query_lca[MAXN];
int djs[MAXN];
bool vis[MAXN];
int Find(int x) {
if (x == djs[x])return x;
return djs[x] = Find(djs[x]);
}
void Tarjan(int p) {
vis[p] = true;
for (int i = start[p]; i; i = edge[i].next) {
if (edge[i].to == fth[p])continue;
fth[edge[i].to] = p;
Tarjan(edge[i].to);
}
for (auto q:query_lca[p])if (vis[q.to])lca[q.id].z = Find(q.to);
djs[p] = fth[p];
}
vector<int> add[MAXN], ers[MAXN];
struct Weight_Tree {
int ch[2], val, wch;
Weight_Tree() {//NOLINT
ch[0] = ch[1] = val = wch = 0;
}
} tree[MAXN * 40];//NOLINT
int tot = 0, root[MAXN], ans[MAXN];
int recycle[MAXN * 40], cnt = 0;//NOLINT
int Build() {
if (cnt == 0)return ++tot;
return recycle[cnt--];
}
void Insert(int p, int l, int r, int x, int y) {
if (l == r) {
tree[p].val += y;
tree[p].wch = tree[p].val > 0 ? l : 0;
return;
}
int mid = (l + r) / 2;
if (l <= x && x <= mid) {
if (tree[p].ch[0] == 0)tree[p].ch[0] = Build();
Insert(tree[p].ch[0], l, mid, x, y);
}
if (mid + 1 <= x && x <= r) {
if (tree[p].ch[1] == 0)tree[p].ch[1] = Build();
Insert(tree[p].ch[1], mid + 1, r, x, y);
}
tree[p].val = max(tree[tree[p].ch[0]].val, tree[tree[p].ch[1]].val);
tree[p].wch = tree[tree[p].ch[0]].val >= tree[tree[p].ch[1]].val ?
tree[tree[p].ch[0]].wch : tree[tree[p].ch[1]].wch;
}
int Merge(int p, int q, int l, int r) {
if (p == 0 || q == 0)return p + q;
if (l == r) {
tree[p].val += tree[q].val;
tree[p].wch = tree[p].val > 0 ? l : 0;
tree[q].ch[0] = tree[q].ch[1] = tree[q].val = tree[q].wch = 0;
recycle[++cnt] = q;
return p;
}
int mid = (l + r) / 2;
tree[p].ch[0] = Merge(tree[p].ch[0], tree[q].ch[0], l, mid);
tree[p].ch[1] = Merge(tree[p].ch[1], tree[q].ch[1], mid + 1, r);
tree[q].ch[0] = tree[q].ch[1] = tree[q].val = tree[q].wch = 0;
recycle[++cnt] = q;
tree[p].val = max(tree[tree[p].ch[0]].val, tree[tree[p].ch[1]].val);
tree[p].wch = tree[tree[p].ch[0]].val >= tree[tree[p].ch[1]].val ?
tree[tree[p].ch[0]].wch : tree[tree[p].ch[1]].wch;
return p;
}
void dfs(int p) {
root[p] = Build();
for (int i = start[p]; i; i = edge[i].next) {
if (edge[i].to == fth[p])continue;
dfs(edge[i].to);
root[p] = Merge(root[p], root[edge[i].to], 1, 1e5);
}
for (auto k:add[p])Insert(root[p], 1, 1e5, k, 1);
for (auto k:ers[p])Insert(root[p], 1, 1e5, k, -1);
ans[p] = tree[root[p]].wch;
}
signed main() {
scanf("%d %d", &n, &m);//NOLINT
for (int i = 1; i < n; i++) {
int u, v;
scanf("%d %d", &u, &v);//NOLINT
edge[2 * i - 1] = {v, start[u]};
start[u] = 2 * i - 1;
edge[2 * i] = {u, start[v]};
start[v] = 2 * i;
}
for (int i = 1; i <= m; i++) {
scanf("%d %d %d", &lca[i].x, &lca[i].y, &lca[i].val);//NOLINT
query_lca[lca[i].x].push_back({lca[i].y, i});
query_lca[lca[i].y].push_back({lca[i].x, i});
}
for (int i = 1; i <= n; i++)djs[i] = i;
Tarjan(1);
for (int i = 1; i <= m; i++) {
add[lca[i].x].push_back(lca[i].val);
add[lca[i].y].push_back(lca[i].val);
ers[lca[i].z].push_back(lca[i].val);
ers[fth[lca[i].z]].push_back(lca[i].val);
}
dfs(1);
for (int i = 1; i <= n; i++)printf("%d\n", ans[i]);
printf("%d\n", tot);
return 0;
}