资料:https://oi-wiki.org/ds/seg/
线段树合并:从两个线段树的根节点开始合并。不可能真的每次建满一颗新的线段树,因此我们需要动态开点线段树。递归合并。即合并到叶子结点时开始合并,然后pushup递归向上。合并时如果其中一个为空,直接返回另一个节点。如果都不为空,合并到其中一个节点上
int merge(int a, int b, int l, int r) {
if (!a) return b;
if (!b) return a;
if (l == r) {
// do something...
return a;
}
int mid = (l + r) >> 1;
tr[a].l = merge(tr[a].l, tr[b].l, l, mid);
tr[a].r = merge(tr[a].r, tr[b].r, mid + 1, r);
pushup(a);
return a;
}
树上的“分发救济粮”需要用树上差分解决。求和的时候又要维护“存放的最多的是哪种救济粮”。维护“最多的救济粮”如果采用最朴素的方法合并时一次就需要O(n),但是同时也想到线段树也能维护“最多的救济粮”,就是麻烦点,但是合并时采用线段树合并的话一次就是O(logn)能满足复杂度要求。
每个节点都有一棵线段树,线段树区间代表类型号在该区间内的救济粮数量,每个线段树节点存储该区间的最多种类的救济粮的类型号,以及数量。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
const int N = 1e5+10,M = 5e6+10;
int fa[N][22],dep[N],rt[N];
int sum[M],cnt=0,res[M],ls[M],rs[M];//动态开点线段树,rs[i]为右子树,ls[i]为左子树
int m,ans[N];
vector<int> g[N];
int n;
void pushup(int x) {
if (sum[ls[x]] < sum[rs[x]]) {
res[x] = res[rs[x]];
sum[x] = sum[rs[x]];
} else {
res[x] = res[ls[x]];
sum[x] = sum[ls[x]];
}
}
int add(int id, int x, int y, int co, int val) {
if (!id) id = ++cnt;
if (x == y) {
sum[id] += val;
res[id] = co;
return id;
}
int mid = (x + y) >> 1;
if (co <= mid)
ls[id] = add(ls[id], x, mid, co, val);
else
rs[id] = add(rs[id], mid + 1, y, co, val);
pushup(id);
return id;
}
int merge(int a,int b,int x,int y){
if(!a) return b;
if(!b) return a;
if(x==y){
sum[a] += sum[b];
return a;
}
int mid = (x + y) >> 1;
ls[a] = merge(ls[a],ls[b],x,mid);
rs[a] = merge(rs[a],rs[b],mid+1,y);
pushup(a);
return a;
}
void initlca(int x){
for(int i=0;i<=20;i++) fa[x][i+1] = fa[fa[x][i]][i];
for(auto y:g[x]){
if(y==fa[x][0]) continue;
fa[y][0] = x;
dep[y] = dep[x]+1;
initlca(y);
}
}
void calc(int x){
for(int i:g[x]){
if(i==fa[x][0]) continue;
calc(i);
rt[x] = merge(rt[x],rt[i],1,100000);
}
ans[x] = res[rt[x]];
if(sum[rt[x]]==0) ans[x] = 0;
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int d=dep[x]-dep[y],i=0;d;d>>=1,i++){
if(d&1) x = fa[x][i];
}
if(x==y) return x;
for(int i=20;i>=0;i--){
if(fa[x][i]!=fa[y][i]) x = fa[x][i],y = fa[y][i];
}
return fa[x][0];
}
int main(){
std::ios::sync_with_stdio(0);
std::cout.tie(0);
std::cin.tie(0);
cin>>n>>m;
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}
initlca(1);
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
rt[a] = add(rt[a],1,100000,c,1);
rt[b] = add(rt[b],1,100000,c,1);
int t = lca(a,b);
rt[t] = add(rt[t],1,100000,c,-1);
rt[fa[t][0]] = add(rt[fa[t][0]],1,100000,c,-1);
}
calc(1);
for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
return 0;
}