这道题好水啊。。。不知道为什么Luogu上给到紫色难度。信息课无聊就秒掉了。。。
很容易想到将每两个点之间的点权+1,直接树剖/差分乱搞即可。
但是要注意,\(A_2\)到\(A_N\)之间的点被当成起点和终点加了两次,所以输出的时候要-1。
#include <bits/stdc++.h>
const int max_n=300000+5;
int N,cnt;
int top[max_n],siz[max_n],son[max_n],father[max_n],depth[max_n];
int first_edge[max_n],A[max_n],C[max_n];
struct Edge
{
int to,next_edge;
}edge[max_n<<1];
inline int read()
{
register int x=0;
register char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
{
x=(x<<1)+(x<<3)+ch-'0';
ch=getchar();
}
return x;
}
inline void add_edge(int x,int y)
{
edge[++cnt].to=y;
edge[cnt].next_edge=first_edge[x];
first_edge[x]=cnt;
}
inline void dfs1(int x,int fa)
{
depth[x]=depth[fa]+1;
father[x]=fa;
siz[x]=1;
int maxx=-1;
for(register int k=first_edge[x];k;k=edge[k].next_edge)
{
if(edge[k].to!=fa)
{
dfs1(edge[k].to,x);
siz[x]+=siz[edge[k].to];
if(siz[edge[k].to]>maxx)
{
maxx=siz[edge[k].to];
son[x]=edge[k].to;
}
}
}
}
inline void dfs2(int x,int topf)
{
top[x]=topf;
if(!son[x]) return;
dfs2(son[x],topf);
for(register int k=first_edge[x];k;k=edge[k].next_edge)
if(edge[k].to!=father[x] && edge[k].to!=son[x]) dfs2(edge[k].to,edge[k].to);
return;
}
inline int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]]) std::swap(x,y);
x=father[top[x]];
}
return depth[x]<depth[y]?x:y;
}
inline void dfs(int x)
{
for(register int k=first_edge[x];k;k=edge[k].next_edge)
{
if(edge[k].to!=father[x])
{
dfs(edge[k].to);
C[x]+=C[edge[k].to];
}
}
}
int main()
{
int x,y,lca;
N=read();
for(register int i=1;i<=N;++i)
A[i]=read();
for(register int i=1;i<N;++i)
{
x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
dfs1(A[1],0),dfs2(A[1],A[1]);
for(register int i=2;i<=N;++i)
{
lca=LCA(A[i],A[i-1]);
++C[A[i]],++C[A[i-1]],--C[lca],--C[father[lca]];
}
dfs(A[1]);
for(register int i=2;i<=N;++i)
--C[A[i]];
for(register int i=1;i<=N;++i)
printf("%d\n",C[i]);
return 0;
}