[BZOJ 3307] 雨天的尾巴
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=3307
[算法]
考虑树上差分 :
在路径x-y上每个点放一个物品c , 等价于 :
在x到根节点的路径上放一个物品c , 在y到根节点的路径上放一个物品c ,
然后在x和y的最近公共祖先到根节点的路径上删除一个物品c , 在x和y的最近公共祖先的父亲到根节点的路径上删除一个物品c
不妨对于每个点构建一棵权值线段树
在DFS计算答案的时候线段树合并 , 即可
时间复杂度 : O(NlogN)(N , M同阶)
[代码]
#include<bits/stdc++.h> using namespace std; const int N = 100010; const int MAXP = 5000005; typedef long long ll; typedef long double ld; typedef unsigned long long ull; struct edge { int to , nxt; } e[N << 1]; int n , m , tot , len; int rt[N] , depth[N] , head[N] , ans[N] , size[N] , son[N] , top[N] , fa[N] , tmp[N] , x[N] , y[N] , z[N]; struct Segment_Tree { int sz; Segment_Tree() { sz = 0; } struct Node { int mx , pos; int lc , rc; } a[MAXP]; inline int merge(int x , int y , int l , int r) { if (x == 0 || y == 0) return x + y; if (l == r) { a[x].mx += a[y].mx; a[x].pos = l; } int mid = (l + r) >> 1; a[x].lc = merge(a[x].lc , a[y].lc , l , mid); a[x].rc = merge(a[x].rc , a[y].rc , mid + 1 , r); update(x); return x; } inline void update(int x) { if (!a[x].lc && !a[x].rc) return; if (a[x].lc && !a[x].rc) { a[x].mx = a[a[x].lc].mx; a[x].pos = a[a[x].lc].pos; } if (!a[x].lc && a[x].rc) { a[x].mx = a[a[x].rc].mx; a[x].pos = a[a[x].rc].pos; } if (a[x].lc && a[x].rc) { if (a[a[x].lc].mx >= a[a[x].rc].mx) { a[x].mx = a[a[x].lc].mx; a[x].pos = a[a[x].lc].pos; } else { a[x].mx = a[a[x].rc].mx; a[x].pos = a[a[x].rc].pos; } } } inline void modify(int &now , int l , int r , int x , int value) { if (!now) now = ++sz; if (l == r) { a[now].mx += value; a[now].pos = l; return; } int mid = (l + r) >> 1; if (mid >= x) modify(a[now].lc , l , mid , x , value); else modify(a[now].rc , mid + 1 , r , x , value); update(now); } inline int query(int x) { if (a[rt[x]].mx <= 0) return 0; else return a[rt[x]].pos; } } SGT; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v) { ++tot; e[tot] = (edge){v , head[u]}; head[u] = tot; } inline void dfs1(int u , int father) { depth[u] = depth[father] + 1; fa[u] = father; size[u] = 1; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == father) continue; dfs1(v , u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } inline int dfs2(int u , int fa , int t) { top[u] = t; if (son[u]) dfs2(son[u] , u , t); for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || v == son[u]) continue; dfs2(v , u , v); } } inline int lca(int x , int y) { while (top[x] != top[y]) { if (depth[top[x]] > depth[top[y]]) swap(x , y); y = fa[top[y]]; } if (depth[x] < depth[y]) return x; else return y; } inline void calc(int u , int father) { for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == father) continue; calc(v , u); rt[u] = SGT.merge(rt[u] , rt[v] , 1 , len); } ans[u] = tmp[SGT.query(u)]; } int main() { read(n); read(m); for (int i = 1; i < n; i++) { int x , y; read(x); read(y); addedge(x , y); addedge(y , x); } dfs1(1 , 0); dfs2(1 , 0 , 1); for (int i = 1; i <= m; i++) { read(x[i]); read(y[i]); read(z[i]); tmp[i] = z[i]; } sort(tmp + 1 , tmp + m + 1); len = unique(tmp + 1 , tmp + m + 1) - tmp - 1; for (int i = 1; i <= m; i++) z[i] = lower_bound(tmp + 1 , tmp + len + 1 , z[i]) - tmp; for (int i = 1; i <= m; i++) { SGT.modify(rt[x[i]] , 1 , len , z[i] , 1); SGT.modify(rt[y[i]] , 1 , len , z[i] , 1); int Lca = lca(x[i] , y[i]); SGT.modify(rt[Lca] , 1 , len , z[i] , -1); if (fa[Lca]) SGT.modify(rt[fa[Lca]] , 1 , len , z[i] , -1); } calc(1 , 0); for (int i = 1; i <= n; i++) printf("%d\n" , ans[i]); return 0; }