从a跑到b
l=lca(a,b)//倍增
用差分的思想要a到b上所经过的点经过次数都+1
那么让从a点+1,b点+1,l点-1,,fa[l][0](l的父亲-1);
如何记录?
一个点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,0,1,0);
add2(fa[l][0],dep[a]-dep[l]+1,-1,0);//时间为dep之差
add2(b,dep[a]-dep[l]*2,1,1);
add2(l,dep[a]-dep[l]*2,-1,1);
如果检查员在i点,jcy[i]表示在i点的时间
如果是从a出发到根,dep[a]-dep[i]+t=jcy[i],dep[a]+t=jcy[i]+dep[i]
从根出发到a,t+dep[i]=jvy[i],t=jcy[i]-dep[i]
只要满足这个等式就可以被观察到
jcy[i]-dep[i]可能小于0,所以所有等式两边+n(点的总数)
因为a肯定在i的子树里,所以求可以被在a的检查员观察到时是不会影响在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;
}