传送门
解析:
据说这是NOIP历年最难一道题。。但是真的没有宝藏难啊我觉得。。。
思路:
答案分两类统计,一种是子树中过来,一种是其他地方过来。那么路径就被拆分成两部分了,一部分是 S − > l c a S->lca S−>lca,一部分是 l c a − > T lca->T lca−>T,两部分分别对应两种答案的统计,这就可以树上差分了。
第一种:从子树中经过。设统计答案的点为
u
u
u
子树中为起点则必须要满足
d
e
p
u
+
w
u
=
d
e
p
S
dep_u+w_u=dep_S
depu+wu=depS,即统计子树内有多少个深度为
d
e
p
u
+
w
u
dep_u+w_u
depu+wu的点,这个就是树上差分的基础应用了。
第二种:从其他子树来。设统计答案的点为
u
u
u
则需要记录入答案的路径需要满足
L
C
A
(
u
,
S
)
=
=
L
C
A
(
S
,
T
)
LCA(u,S)==LCA(S,T)
LCA(u,S)==LCA(S,T),不过这个不需要体现在代码上。而满足路径长度则需要
w
u
−
d
e
p
u
=
d
e
p
l
c
a
×
2
−
d
e
p
S
w_u-dep_u=dep_{lca}\times 2-dep_S
wu−depu=deplca×2−depS。
这个等式左边只和
u
u
u有关,右边和
u
u
u没有关系,同样树上差分解决。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=300005;
int bin1[N<<1],bbb[N<<1];
int *cs bin2=bbb+N;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int w[N];
int fa[N],top[N],dep[N],siz[N],son[N];
inline void dfs1(int u){
siz[u]=1;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
inline void dfs2(int u){
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
if(son[u]==v)top[v]=top[u];
else top[v]=v;
dfs2(v);
}
}
inline void tree_dissection(int root=1){
dfs1(root);
top[root]=root;
dfs2(root);
}
inline int LCA(int u,int v){
while(top[u]^top[v]){
if(dep[top[u]]>dep[top[v]])swap(u,v);
v=fa[top[v]];
}
return dep[u]>dep[v]?v:u;
}
vector<int> pos1[N],pos2[N],add1[N],add2[N];
int ans[N];
inline void dfs(int u){
int pre1=bin1[dep[u]+w[u]],pre2=bin2[w[u]-dep[u]];
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
dfs(v);
}
for(int re i=0;i<pos1[u].size();++i)bin1[pos1[u][i]]+=add1[u][i];
for(int re i=0;i<pos2[u].size();++i)bin2[pos2[u][i]]+=add2[u][i];
ans[u]+=bin1[dep[u]+w[u]]-pre1+bin2[w[u]-dep[u]]-pre2;
}
int n,m;
signed main(){
n=getint();
m=getint();
for(int re i=1;i<n;++i){
int u=getint(),v=getint();
addedge(u,v);
}
tree_dissection();
for(int re i=1;i<=n;++i)
w[i]=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint(),lca=LCA(u,v);
pos1[u].push_back(dep[u]);add1[u].push_back(1);
pos1[lca].push_back(dep[u]);add1[lca].push_back(-1);
pos2[v].push_back(dep[u]-2*dep[lca]);add2[v].push_back(1);
pos2[fa[lca]].push_back(dep[u]-2*dep[lca]);add2[fa[lca]].push_back(-1);
}
dfs(1);
for(int re i=1;i<=n;++i)printf("%d ",ans[i]);
return 0;
}