题目大意就是按照他给的顺序遍历树,问每个节点会经过几次,最后的那个要减1

类似前缀和的思想
从起点x到终点y,只需给x,y两个结点加1,给LCA(x,y),fa[LCA(x,y)]减1,最后做一次从底到根的递推即可求出每个点在多少条链上
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
#define N 300010
struct edge
{
int to,next;
}e[N<<2];
int head[N<<2];
int cnt;
int n;
int id;
int x,y;
int a[N],ans[N];
int siz[N],dep[N],fa[N],top[N],son[N],dfn[N];
inline int getint()
{
int x=0,f=1;char ch=getchar();
while (ch>'9' || ch<'0') {if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void link(int x,int y)
{
e[++cnt]=(edge){y,head[x]};
head[x]=cnt;
}
void dfs(int x)
{
siz[x]=1;
son[x]=0;
dfn[++id]=x;
for (int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if (fa[x]!=v)
{
fa[v]=x;
dep[v]=dep[x]+1;
dfs(v);
siz[x]+=siz[v];
if (siz[v]>siz[son[x]])
son[x]=v;
}
}
}
void dfs2(int x,int d)
{
top[x]=d;
if (son[x])
dfs2(son[x],d);
for (int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if (fa[x]!=v && son[x]!=v)
dfs2(v,v);
}
}
int lca(int x,int y)
{
while (top[x]!=top[y])
{
int a=top[x];
int b=top[y];
if (dep[a]<dep[b])
swap(a,b),swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y] ? x : y;
}
int main()
{
n=getint();
for (int i=1;i<=n;i++)
a[i]=getint();
for (int i=1;i<n;i++)
{
x=getint();
y=getint();
link(x,y);
link(y,x);
}
dfs(1);
dfs2(1,1);
for (int i=2;i<=n;i++)
{
int u=a[i-1],v=a[i],w=lca(u,v);
ans[u]++;
ans[v]++;
ans[w]--;
ans[fa[w]]--;
}
for (int i=n;i>=1;i--)
ans[fa[dfn[i]]]+=ans[dfn[i]];
for (int i=1;i<=n;i++)
if (a[1]!=i)
printf("%d
",ans[i]-1);
else
printf("%d
",ans[i]);
return 0;
}