我们在每一个节点上建立一个动态开点的线段树,最初只有根节点,线段树的叶节点下标维护的是物品类型,值为这种物品的个数。对于将x到y的路径上同时发放类型为w的物品,我们可以采用树上差分。这是对于点的差分,方法为:v[x] += 1, v[y] += 1, v[lca(x,y)] -= 1, v[ fa[lca(x, y)] -=1。对于普通的树上差分,就是再进行一遍dfs,统计前缀和。但是这道题的每一个节点都是一棵线段树,我们可以采用线段树合并来快速维护前缀和。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
pair<int, int> PII;
int anc[N][22], dep[N];
int n, m, root[N], head[N], cnt, idx, rg = 1e5, ans[N];
struct Node {
int lc, rc;
int v, pos;
} tr[N * 50];
struct Edge {
int v, nxt;
} e[N << 1];
void AddEdge(int u, int v) {
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
void dfs(int u, int father) {
anc[u][0] = father;
dep[u] = dep[father] + 1;
for(int i = 1; i <= 20; i ++) {
anc[u][i] = anc[anc[u][i - 1]][i - 1];
}
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if( v == father) continue;
dfs(v, u);
}
}
int lca(int x, int y) {
if( dep[x] < dep[y]) swap(x, y);
for(int i = 20; i >= 0; -- i ) {
if( dep[anc[x][i]] >= dep[y])
x = anc[x][i];
}
if( x == y) return x;
for(int i = 20; i >= 0; -- i) {
if( anc[x][i] != anc[y][i])
x = anc[x][i], y = anc[y][i];
}
return anc[x][0];
}
void pushup(int u) {
if( tr[tr[u].lc].v >= tr[tr[u].rc].v) {
tr[u].v = tr[tr[u].lc].v;
tr[u].pos = tr[tr[u].lc].pos;
} else {
tr[u].v = tr[tr[u].rc].v;
tr[u].pos = tr[tr[u].rc].pos;
}
}
void insert(int u, int l, int r, int k, int v) {
if( l == r) {
tr[u].v += v;
tr[u].pos = l;
return ;
}
int mid = l + r >> 1;
if( k <= mid) {
if( !tr[u].lc) tr[u].lc = ++ idx;
insert(tr[u].lc, l, mid, k, v);
}
else {
if( !tr[u].rc) tr[u].rc = ++ idx;
insert(tr[u].rc, mid + 1, r, k, v);
}
pushup(u);
}
int merge(int p, int q, int l, int r) {
if( !p || !q)
return p + q;
if( l == r) {
tr[p].v += tr[q].v;
return p;
}
int mid = l + r >> 1;
tr[p].lc = merge(tr[p].lc, tr[q].lc, l, mid);
tr[p].rc = merge(tr[p].rc, tr[q].rc, mid + 1, r);
pushup(p);
return p;
}
void Sum(int u, int fa) {
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if( v == fa) continue;
Sum(v, u);
root[u] = merge(root[u], root[v], 1, rg);
}
if( tr[root[u]].v == 0)
ans[u] = 0;
else ans[u] = tr[root[u]].pos;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) root[i] = i;
idx = n;
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v), AddEdge(v, u);
}
dfs(1, 0);
while(m --) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
insert(root[u], 1, rg, w, 1);
insert(root[v], 1, rg, w, 1);
int t = lca(u, v);
insert(root[t], 1, rg, w, -1);
insert(root[anc[t][0]], 1, rg, w, -1);
}
Sum(1, 0);
for(int i = 1; i <= n; i ++)
printf("%d
", ans[i]);
return 0;
}