一个人从a跑到b。
l=lca(a,b)//倍增
f[l][0]:为l的爸爸。
把他拆成四个人。
分别从a跑到根的人。
从f[l][0]跑到根的人。
从根跑到b的人。
从根跑到l的人。//差分的思想,
我们要让a到b最短路径上所有的点经过次数都+1,并记录时间
那么在差分数组上让a点+1,b点+1,l点-1,,fa[l][0](l的父亲)-1;
如何记录每一个人从a跑到b的信息?
一个点a记四个信息(a,t,d,p):
a:起点(如果是从a出发)/终点(如果是从根出发)为a;
t:表示从a出发时间
d:当这个人跑过时经过次数+1还是-1;
p:是从a出发到根(0)还是从根出发到a(1)
我们对于一个人记录4个点的信息这四个点分别为a,b,l,fa[l][0](l的父亲),(记录用邻接链表)
add2(a,t,d,p)//加入一条信息,表示如果p == 0,有一个人在t从a点出发,他要走到根,他所经过的点的次数应该加d;
表示如果p == 1,有一个人在t从根出发,他要走到a,他所经过的点的次数应该加d;
add2(a,0,1,0);
add2(fa[l][0],dep[a]-dep[l]+1,-1,0);//从fa[l][0]为到l后的后一秒出发时间为dep之差
add2(b,dep[a]-dep[l]*2,1,1);//在没拆之前这个人要在dis(a,b) = dep[a]+dep[b]-dep[l]-dep[l] 时跑到b,那么他从根出发时间为dep[a]-dep[l] -dep[l];他要花dep[b]时间从根跑到b.
add2(l,dep[a]-dep[l]*2,-1,1);//没拆之前这个人要在dep[a]-dep[l]的时间到l,那么拆了后他从根出发的时间则为dep[a]-dep[l]*2
如果检查员在i点,jcy[i]表示检查员在i点的时间
如果人是从a出发到根,dep[a]-dep[i]+t=jcy[i],dep[a]+t=jcy[i]+dep[i]//t是从a出发的时间
从人是根出发到a, t+dep[i]=jcy[i],t=jcy[i]-dep[i]
(只要满足这个等式就可以被观察到,即i观察到的人数+1)
jcy[i]-dep[i]可能小于0,所以所有等式两边+n(点的总数)
因为a肯定在i的子树里,所以求可以被在jcy[a]时被站在a的检查员观察到的人数时是不会影响在jcy[int]时被站在i点的检查员观察到的人数的。
引进tong1[i](表示从a出发到根,被在i点的检查员观察到的人数)
tong2[i](表示从根出发到a,被在i点的检查员观察到的人数)
#include<iostream>
#include<cstdio>
using namespace std;
int ans[300010],n,m,jcy[300010];
int tov[600010],nex[600010],h[300010],tp;
int tpp,nexx[1200010],tod[1200010],top[1200010],tot[1200010],hh[300010];
int tong1[1000010],tong2[1000010];
int dep[300010]={0};
int fa[300010][20]={0};
bool vis[300010]={0};
void add(int x,int y)
{
tp++;
nex[tp]=h[x];
tov[tp]=y;
h[x]=tp;
}
void add2(int qi,int t,int d,int p)
{
tpp++;
nexx[tpp]=hh[qi];
tod[tpp]=d;
top[tpp]=p;
tot[tpp]=t;
hh[qi]=tpp;
}
void dfs(int v)
{
vis[v]=1;
for(int i=h[v];i;i=nex[i])
if (!vis[tov[i]])
{
dep[tov[i]]=dep[v]+1;
fa[tov[i]][0]=v;
dfs(tov[i]);
}
}
int lca(int x,int y)
{
if (dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if (x==y) return x;
for(int i=19;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void solve(int x)
{
int x1=jcy[x]+dep[x]+n,x2=jcy[x]-dep[x]+n;
int val1=tong1[x1],val2=tong2[x2];
for(int i=hh[x];i;i=nexx[i])
{
if(top[i]==0)tong1[tot[i]+dep[x]+n]+=tod[i];
else tong2[tot[i]+n]+=tod[i];
}
for(int i=h[x];i;i=nex[i])
{
int v=tov[i];
if(dep[v]>dep[x])solve(v);
}
ans[x]=tong1[x1]+tong2[x2]-val1-val2;
}
int main()
{
//freopen("running.in","r",stdin);
//freopen("running.out","w",stdout);
cin>>n>>m;
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dep[1]=0;dep[0]=-1;
dfs(1);
for(int i=1;i<=19;i++)
for(int j=1;j<=n;j++)
fa[j][i]=fa[fa[j][i-1]][i-1];
for(int i=1;i<=n;i++)
{
scanf("%d",&jcy[i]);
}
for(int i=1;i<=m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
int l=lca(a,b);
add2(a,0,1,0);
add2(fa[l][0],dep[a]-dep[l]+1,-1,0);
add2(b,dep[a]-dep[l]*2,1,1);
add2(l,dep[a]-dep[l]*2,-1,1);
}
solve(1);
for(int i=1;i<=n;i++)
{
printf("%d ",ans[i]);
}
return 0;
}