题目链接:Click here
Solution:
首先orz@WYBIACX,蒟蒻本来不怎么会,看了大佬题解才会
写完这题后有所收获,所以特此总结一下
对于每条路径,我们可以把它拆成(u ightarrow lca(u,v))和(lca(u,v) ightarrow v)来考虑
对于(u ightarrow lca)这条路径上的点(x),显然仅当(dep[x]+w[x]=dep[u])时,(u)才会对(x)造成造成贡献
则第一次计算,我们对一个点,定义它的权值为(dep[x]),用一个桶去维护数量
对于(lca ightarrow v)这条路经上的点,首先就可以得出当(dis(u,x)=w[x])时,(u)对(x)可以造成贡献
但是我们如果直接这样算,是无法利用桶去维护的,则考虑如何转化
(dis(u,x)-dep[x]=w[x]-dep[x]),(dis(u,v)-dep[v]=w[x]-dep[x])
则对于(lca ightarrow v)这条路径上的点,当(dis(u,v)-dep[v]=w[x]-dep[x])时有贡献,我们同样用一个桶来维护
要注意的是一条路径是不能对他们(lca)以上的点造成影响的,所以要在他们的(lca)处在桶内减掉他们
还有,当(lca)可以观测到这条路径上的点时,它会被算两次,我们应该减去多算的
最后,桶的下标并不一定是正数,所以我们要把下标值加上(maxn)
Code:
#include<bits/stdc++.h>
const int N=3e5+11;
using namespace std;
int n,m,cnt,head[N],w[N],fa[N];
int son[N],sz[N],dep[N],ans[N];
int num[N],top[N],bucket[N*3];
vector<int> v1[N],v2[N],v3[N];
struct Edge{int nxt,to;}edge[N<<1];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void ins(int x,int y){
edge[++cnt].nxt=head[x];
edge[cnt].to=y;head[x]=cnt;
}
void dfs1(int x,int fat){
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(y==fat) continue;
fa[y]=x;dep[y]=dep[x]+1;
dfs1(y,x);sz[x]+=sz[y];
if(sz[y]>sz[son[x]]) son[x]=y;
}++sz[x];
}
void dfs2(int x,int topx){
top[x]=topx;
if(!son[x]) return ;
dfs2(son[x],topx);
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(y==fa[x]||y==son[x]) continue;
dfs2(y,y);
}
}
int Lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}return dep[x]<dep[y]?x:y;
}
int dis(int x,int y){
return dep[x]+dep[y]-(dep[Lca(x,y)]<<1);
}
void calc1(int x){
int pre=bucket[dep[x]+w[x]+N];
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(y==fa[x]) continue;
calc1(y);
}
bucket[dep[x]+N]+=num[x];
ans[x]+=bucket[dep[x]+w[x]+N]-pre;
for(int i=0;i<v1[x].size();i++)
--bucket[dep[v1[x][i]]+N];
}
void calc2(int x){
int pre=bucket[w[x]-dep[x]+N];
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(y==fa[x]) continue;
calc2(y);
}
for(int i=0;i<v3[x].size();i++)
++bucket[dis(x,v3[x][i])-dep[x]+N];
ans[x]+=bucket[w[x]-dep[x]+N]-pre;
for(int i=0;i<v2[x].size();i++)
--bucket[v2[x][i]+N];
}
signed main(){
n=read(),m=read();
for(int i=1;i<n;i++){
int x=read(),y=read();
ins(x,y),ins(y,x);
}
for(int i=1;i<=n;i++) w[i]=read();
dfs1(1,0);dfs2(1,1);
for(int i=1;i<=m;i++){
int x=read(),y=read();
num[x]++;int lca=Lca(x,y);
v1[lca].push_back(x);
v2[lca].push_back(dis(x,y)-dep[y]);
v3[y].push_back(x);
if(dep[lca]+w[lca]==dep[x]) --ans[lca];
}
calc1(1);calc2(1);
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}