【题目链接】
【思路要点】
- 路径\((x,y)\)可以看做路径\((x,root)\)+路径\((y,root)\)-路径\((Lca,root)\)-路径\((father_{Lca},y)\)。
- 依据这一点进行树上差分和线段树合并即可。
- 时间复杂度\(O(NLogN)\)(\(N\)、\(M\)同阶)。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXP = 5000005; const int MAXN = 100005; const int MAXLOG = 20; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct SegmentTree { struct Node { int lc, rc; bool leaf; int Max; } a[MAXP]; int n, size; void init(int x) { n = x; size = 0; } void update(int root) { a[root].Max = max(a[a[root].lc].Max, a[a[root].rc].Max); } void modify(int &root, int l, int r, int val, int d) { if (root == 0) root = ++size; if (l == r) { a[root].leaf = true; a[root].Max += d; return; } int mid = (l + r) / 2; if (mid >= val) modify(a[root].lc, l, mid, val, d); else modify(a[root].rc, mid + 1, r, val, d); update(root); } void modify(int &root, int val, int d) { modify(root, 1, n, val, d); } int merge(int x, int y) { if (x == 0 || y == 0) return x + y; if (a[x].leaf) { a[x].Max += a[y].Max; return x; } a[x].lc = merge(a[x].lc, a[y].lc); a[x].rc = merge(a[x].rc, a[y].rc); update(x); return x; } int query(int root, int l, int r) { if (l == r) return l; int mid = (l + r) / 2; if (a[a[root].lc].Max >= a[a[root].rc].Max) return query(a[root].lc, l, mid); else return query(a[root].rc, mid + 1, r); } int query(int root) { if (a[root].Max == 0) return 0; else return query(root, 1, n); } } ST; vector <int> a[MAXN]; int n, father[MAXN][MAXLOG], depth[MAXN]; int m, x[MAXN], y[MAXN], val[MAXN]; int tot, tmp[MAXN], root[MAXN], ans[MAXN]; void work(int pos, int fa) { father[pos][0] = fa; depth[pos] = depth[fa] + 1; for (int i = 1; i < MAXLOG; i++) father[pos][i] = father[father[pos][i - 1]][i - 1]; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) work(a[pos][i], pos); } int lca(int x, int y) { if (depth[x] < depth[y]) swap(x, y); for (int i = MAXLOG - 1; i >= 0; i--) if (depth[father[x][i]] >= depth[y]) x = father[x][i]; if (x == y) return x; for (int i = MAXLOG - 1; i >= 0; i--) if (father[x][i] != father[y][i]) { x = father[x][i]; y = father[y][i]; } return father[x][0]; } void getans(int pos, int fa) { for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i] != fa) { getans(a[pos][i], pos); root[pos] = ST.merge(root[pos], root[a[pos][i]]); } ans[pos] = tmp[ST.query(root[pos])]; } int main() { read(n), read(m); for (int i = 1; i <= n - 1; i++) { int x, y; read(x), read(y); a[x].push_back(y); a[y].push_back(x); } work(1, 0); for (int i = 1; i <= m; i++) read(x[i]), read(y[i]), read(val[i]), tmp[i] = val[i]; sort(tmp + 1, tmp + m + 1); tot = unique(tmp + 1, tmp + m + 1) - tmp - 1; ST.init(tot); for (int i = 1; i <= m; i++) { int z = lca(x[i], y[i]); int num = lower_bound(tmp + 1, tmp + tot + 1, val[i]) - tmp; ST.modify(root[x[i]], num, 1); ST.modify(root[y[i]], num, 1); ST.modify(root[z], num, -1); ST.modify(root[father[z][0]], num, -1); } getans(1, 0); for (int i = 1; i <= n; i++) writeln(ans[i]); return 0; }