题目:
题目链接:[LUOGU [Vani有约会]雨天的尾巴]
题解:
这个题,,,就是线段树合并的板子,加上一个树上差分操作即可。至于怎么树上差分,可以先想一下在序列中差分,因为这里是赋值的操作了,所以在序列中啊,就是在序列的首位出加一减一就可。这样的思想转化到树上对于树上的距离就是重在四个点上,
x
x
x,
y
y
y,
l
c
a
(
x
,
y
)
lca(x,y)
lca(x,y),
f
a
[
l
c
a
(
x
,
y
)
]
fa[lca(x,y)]
fa[lca(x,y)],主要是由于是在赋值为z,所以只对
x
x
x,
y
y
y这两个点
+
1
+1
+1,在
l
c
a
(
x
,
y
)
lca(x,y)
lca(x,y),
f
a
[
l
c
a
(
x
,
y
)
]
fa[lca(x,y)]
fa[lca(x,y)]处
−
1
-1
−1即可。(可以自己手画个图理解理解)。之后就直接用权值线段树进行合并即可。
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int sea=1e5+7;
struct hit{int ls,rs,max,sum,ans;}tr[sea*60];
struct see{int ver,next;}e[sea<<1];
int n,m,tot,seg,root[sea<<1],last[sea<<1],fa[22][sea<<1],deep[sea<<1];
void add(int x,int y){e[++tot].ver=y;e[tot].next=last[x];last[x]=tot;}
void DFS(int x,int f)
{
fa[0][x]=f; deep[x]=deep[f]+1;
for(int i=last[x];i;i=e[i].next)
if(e[i].ver!=fa[0][x]) DFS(e[i].ver,x);
}
int lca(int x,int y)
{
if(deep[x]>deep[y]) swap(x,y);
for(int d=deep[y]-deep[x],i=0;d;d>>=1,i++) if(d&1) y=fa[i][y];
if(x==y) return x;
for(int i=21;i>=0;--i) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
return fa[0][x];
}
void up(int k)
{
int l=tr[k].ls,r=tr[k].rs;
if(tr[l].sum>=tr[r].sum) tr[k].max=tr[l].max,tr[k].sum=tr[l].sum;
else tr[k].max=tr[r].max,tr[k].sum=tr[r].sum;
}
void build(int &k,int l,int r,int val,int tt)
{
if(!k) k=++seg;
if(l==r) {tr[k].max=l,tr[k].sum+=tt;return ;}
int mid=(l+r)/2;
if(val<=mid) build(tr[k].ls,l,mid,val,tt);
else build(tr[k].rs,mid+1,r,val,tt);
up(k);
}
int incor(int x,int y,int l,int r)
{
if(!x) return y; if(!y) return x;
if(l==r){tr[x].sum+=tr[y].sum; return x;}
int mid=(l+r)/2;
tr[x].ls=incor(tr[x].ls,tr[y].ls,l,mid);
tr[x].rs=incor(tr[x].rs,tr[y].rs,mid+1,r);
up(x); return x;
}
void dfs(int x,int fa)
{
for(int i=last[x];i;i=e[i].next)
{
int y=e[i].ver; if(y==fa) continue;
dfs(y,x); root[x]=incor(root[x],root[y],1,sea);
}
if(tr[root[x]].sum) tr[x].ans=tr[root[x]].max;
}
int main()
{
n=read(); m=read();
for(int i=1,x,y;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
seg=n; deep[0]=0; DFS(1,0);
for(int i=1;1<<i<=n;i++) for(int j=1;j<=n;j++)
if(fa[i-1][j]<0) fa[i][j]=-1;else fa[i][j]=fa[i-1][fa[i-1][j]];
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read(); int ins=lca(x,y);
build(root[x],1,sea,z,1); build(root[y],1,sea,z,1);
build(root[ins],1,sea,z,-1); build(root[fa[0][ins]],1,sea,z,-1);
}
dfs(1,0); for(int i=1;i<=n;i++) printf("%d\n",tr[i].ans);
return 0;
}