线段树合并差分
链接:P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)****
题意:给定一棵树,多次修改将 x 到 y 的路径上的点均加上 z 号颜色,最后求出每个点的最多出现的颜色。出现颜色次数一样时取编号最小的那个。
题解:多次操作后最后再求答案,那么其实操作就不需要实时查询了,可以采用差分的形式在 x 到 y 的链上打标记,最后在求差分的前缀和即为答案。不一样的是,差分和求前缀和均是在线段树上通过更新,合并来实现的。对于 x 到 y 路径上的点,只需要求出 lca ,在 x,y 处分别打上加入 z 的记号,在 lca 及其父节点上打上 -z 的记号,然后计算子树时直接更新合并即可。注意可能有点是不存在任意颜色的,输出 0 。当所有颜色均出现却没有在某个点上时,可能会出现将区间内 [1,m] 内输出 1 。其实应该是 0 。所以更新区间应该为 [0,m] 。保证出现次数为 0 时编号最小的是 0 。
// #pragma GCC optimize("Ofast")
// #pragma GCC optimize("unroll-loops")
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<functional>
#include<queue>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
using ll=long long;
using P=pair<int,int>;
const ll inf=1e18;
struct Merge{
static constexpr int N=1e5+5;
int n,now;
vector<int>t,ls,rs,mx,va,rt;
Merge(int x=N):n((x+5)*50),t(n),ls(n),rs(n),mx(n),va(n),rt(x+5),now(0){}
void pushup(int k){
int l=ls[k],r=rs[k];
if(mx[l]>mx[r])
{
mx[k]=mx[l];
va[k]=va[l];
}
else if(mx[l]<mx[r])
{
mx[k]=mx[r];
va[k]=va[r];
}
else
{
mx[k]=mx[l];
va[k]=min(va[l],va[r]);
}
}
void update(int&u,int l,int r,int pos,int w){
if(!u)u=++now;
if(l==r)
{
mx[u]+=w;
va[u]=l;
return;
}
int mid=l+r>>1;
if(pos<=mid)update(ls[u],l,mid,pos,w);
else update(rs[u],mid+1,r,pos,w);
pushup(u);
}
void merge(int&u,int&v,int l,int r){
if(!u||!v){u=u|v; return;}
if(l==r)
{
va[u]=l;
mx[u]+=mx[v];
return;
}
int mid=l+r>>1;
merge(ls[u],ls[v],l,mid);
merge(rs[u],rs[v],mid+1,r);
pushup(u);
}
}tr;
void solve()
{
int n,m; cin>>n>>m;
vector<vector<int>>ed(n+1);
for(int i=1,u,v;i<n;i++)
{
cin>>u>>v;
ed[u].push_back(v);
ed[v].push_back(u);
}
vector<int>ans(n+1);
vector<vector<P>>ch(n+1);
vector<int>dep(n+1),lg(n+1);
vector<vector<int>>f(n+1,vector<int>(20));
for(int i=1;i<=n;i++)lg[i]=lg[i-1]+(!(i&i-1));
auto dfs=[&](auto dfs,int x,int fa)->void{
dep[x]=dep[fa]+1,f[x][0]=fa;
for(int i=1;i<20;i++)
{
f[x][i]=f[f[x][i-1]][i-1];
}
for(auto y:ed[x])
{
if(y==fa)continue;
dfs(dfs,y,x);
}
};
auto lca=[&](int x,int y){
if(dep[x]<dep[y])swap(x,y);
while(dep[x]>dep[y])
{
x=f[x][lg[dep[x]-dep[y]]-1];
}
if(x==y)return x;
for(int i=19;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i],y=f[y][i];
}
}
return f[x][0];
};
dfs(dfs,1,0);
int mx=0;
for(int i=1,u,v,z,w;i<=m;i++)
{
cin>>u>>v>>z;
w=lca(u,v);
ch[u].push_back({z,1});
ch[v].push_back({z,1});
ch[w].push_back({z,-1});
ch[f[w][0]].push_back({z,-1});
mx=max(mx,z);
}
auto dfs1=[&](auto dfs1,int x,int fa)->void{
for(auto[a,b]:ch[x])
{
tr.update(tr.rt[x],0,mx,a,b);
}
for(auto y:ed[x])
{
if(y==fa)continue;
dfs1(dfs1,y,x);
tr.merge(tr.rt[x],tr.rt[y],0,mx);
}
ans[x]=tr.va[tr.rt[x]];
};
dfs1(dfs1,1,0);
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<"\n";
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t=1; //cin>>t;
while(t--)solve();
return 0;
}