题目
题解
看到某Yuta的树总结觉得LCA+树上差分挺好写而且差分没写过准备水一发结果水了一上午qwq。因为第一次写树上差分和树剖求LCA,结果树剖版子某处打错了。。(而且差分点和差分边还是有一定区别的)。
这题可以用树剖水部分分,不过n有30w,log方就会被卡了。所以利用差分思想把区间修改转化为点修改。给每个点一个tag表示新增值(貌似怪怪的)。如果有条路径(i,j)需要标记那么进行如下操作
tag(i)++;tag(j)++;tag(LCA(i,j))- -;tag(father(LCA(i,j)))- -;
这样能够达到标记经过的点的效果,请自行脑补如果是经过的边如何标记。
那么就把路径拆分就好了,但是这道题非起始端点会被多算一次(在衔接处),所以统计完后减回来。
题很水,人很蠢。
代码
//QWsin
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=600000+10;
const int maxm=1200000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}
int to[maxn];
int first[maxn],next[maxm],ecnt;
struct Edge{int u,v;Edge(int u=0,int v=0):u(u),v(v){}}e[maxm];
inline void add_edge(int u,int v)
{
next[ecnt]=first[u];first[u]=ecnt;e[ecnt++]=Edge(u,v);
next[ecnt]=first[v];first[v]=ecnt;e[ecnt++]=Edge(v,u);
}
int top[maxn],hv[maxn],sz[maxn],p[maxn],dep[maxn];
int tag[maxn];
int dfs1(int u,int fa,int deep=1)
{
p[u]=fa;dep[u]=deep;sz[u]=1;int msz=0;
for(int i=first[u];i!=-1;i=next[i]) if(e[i].v!=fa){
int lch=dfs1(e[i].v,u,deep+1);
if(lch > msz) msz=lch,hv[u]=e[i].v;
sz[u]+=lch;
}
return sz[u];
}
void dfs2(int u,int Top)
{
top[u]=Top;
if(sz[u]==1) return ;
dfs2(hv[u],Top);
for(int i=first[u];i!=-1;i=next[i])
if(e[i].v!=p[u]&&e[i].v!=hv[u]) dfs2(e[i].v,e[i].v);
}
int LCA(int a,int b)
{
for(;top[a]!=top[b];b=p[top[b]])
if(dep[top[a]] > dep[top[b]]) swap(a,b);
return dep[a]<dep[b]?a:b;
}
int ans[maxn],sum,n;
int dfs3(int cur)
{
int sum=tag[cur];
for(int i=first[cur];i!=-1;i=next[i])
if(e[i].v!=p[cur]) sum+=dfs3(e[i].v);
if(to[1]!=cur) ans[cur]=sum-1;
else ans[cur]=sum; return sum;
}
int main()
{
n=read();memset(first,-1,sizeof(first));
for(int i=1;i<=n;i++) to[i]=read();
for(int i=1;i<n;i++) add_edge(read(),read());
int root=1;
dfs1(root,root);dfs2(root,root);
tag[to[1]]++;tag[to[2]]++;
int lca=LCA(to[1],to[2]);
tag[lca]--;if(lca!=root) tag[p[lca]]--;
for(int i=2;i<n;i++)
{
int lca=LCA(to[i],to[i+1]);
tag[to[i]]++;tag[to[i+1]]++;
tag[lca]--;if(lca!=root) tag[p[lca]]--;
}
dfs3(root);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}