直接进行树链剖分
每一轮,路径上的点加1
最后输出答案时,除起点外的结点权值要减1
只用到区间增减,单点查询和值,因此并不需要线段树来维护
另一种思路:类似前缀和的思想
每一轮,路径上的点加1
最后输出答案时,除起点外的结点权值要减1
只用到区间增减,单点查询和值,因此并不需要线段树来维护
另一种思路:类似前缀和的思想
从起点x到终点y,只需给x,y两个结点加1,给LCA(x,y),fa[LCA(x,y)]减1,最后做一次从底到根的递推即可求出每个点在多少条链上
树剖:
#include<stdio.h>
#include<stdlib.h>
#include<vector>
using namespace std;
vector<int> G[300005];
int a[300005],fa[300005],deep[300005],size[300005],son[300005],top[300005],pos[300005],s[1200005];
int tot=0;
void jh(int* a,int* b)
{
int t=*a;
*a=*b;
*b=t;
}
void dfs1(int x,int f)
{
int i;
fa[x]=f;
size[x]=1;
for(i=0;i<G[x].size();i++)
if(G[x][i]!=f)
{
deep[G[x][i]]=deep[x]+1;
dfs1(G[x][i],x);
size[x]+=size[G[x][i]];
if(size[G[x][i]]>size[son[x]]) son[x]=G[x][i];
}
}
void dfs2(int x,int t)
{
int i;
top[x]=t;
pos[x]=++tot;
if(son[x]>0) dfs2(son[x],t);
for(i=0;i<G[x].size();i++)
if(G[x][i]!=fa[x]&&G[x][i]!=son[x]) dfs2(G[x][i],G[x][i]);
}
void xg(int x,int y)
{
s[x]++;
s[y+1]--;
}
void tree_xg(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]]) jh(&x,&y);
xg(pos[top[x]],pos[x]);
x=fa[top[x]];
}
if(deep[x]>deep[y]) jh(&x,&y);
xg(pos[x],pos[y]);
}
int main()
{
int n,i,x,y;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs1(1,0);
dfs2(1,1);
for(i=1;i<n;i++)
tree_xg(a[i],a[i+1]);
for(i=1;i<=n;i++)
s[i]+=s[i-1];
for(i=1;i<=n;i++)
{
if(i==a[1]) printf("%d\n",s[pos[i]]);
else printf("%d\n",s[pos[i]]-1);
}
return 0;
}