题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有\(n-1\)根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去\(a_1\),再去\(a_2\),......,最后到\(a_n\),去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间\(a_n\)是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入输出格式
输入格式:
第一行一个整数\(n\),表示房间个数第二行\(n\)个整数,依次描述\(a_1-a_n\)
接下来\(n-1\)行,每行两个整数\(x\),\(y\),表示标号\(x\)和\(y\)的两个房间之间有树枝相连。
输出格式:
一共\(n\)行,第\(i\)行输出标号为\(i\)的房间至少需要放多少个糖果,才能让维尼有糖果吃。
输入输出样例
输入样例#1:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出样例#1:
1
2
1
2
1
说明
\(2 \leq n \leq 300000\)
思路:考虑树链剖分+线段树,我们自己手玩样例可以发现,我们按题目中给出的结点访问顺序进行路径修改,最后把每条路径的起点的点权\(-1\)(除了起始结点),就是答案了,然后就是一个树链剖分的裸题了。
代码:
#include<cstdio>
#include<algorithm>
#include<cctype>
#define maxn 300007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
int n,m,head[maxn],d[maxn],son[maxn],siz[maxn],id[maxn],w[maxn];
int num,cnt,sum[maxn<<2],top[maxn],fa[maxn],lazy[maxn<<2];
inline int qread() {
char c=getchar();int num=0,f=1;
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) num=num*10+c-'0';
return num*f;
}
struct node {
int v,nxt;
}e[maxn<<1];
inline void ct(int u, int v) {
e[++num].v=v;
e[num].nxt=head[u];
head[u]=num;
}
inline void pushdown(int rt) {
if(lazy[rt]) {
sum[ls]+=lazy[rt],sum[rs]+=lazy[rt];
lazy[ls]+=lazy[rt],lazy[rs]+=lazy[rt];
lazy[rt]=0;
}
}
void modify(int rt, int l, int r, int L, int R, int val) {
if(L>r||R<l) return;
if(L<=l&&r<=R) {
sum[rt]+=val;
lazy[rt]+=val;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
modify(ls,l,mid,L,R,val),modify(rs,mid+1,r,L,R,val);
}
int query(int rt, int l, int r, int L) {
if(l==r) return sum[rt];
int mid=(l+r)>>1;
pushdown(rt);
if(L<=mid) return query(ls,l,mid,L);
else return query(rs,mid+1,r,L);
}
void dfs1(int u) {
siz[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]) {
d[v]=d[u]+1;
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u, int t) {
id[u]=++cnt;
top[u]=t;
if(son[u]) dfs2(son[u],t);
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
void cal(int x, int y) {
int fx=top[x],fy=top[y];
while(fx!=fy) {
if(d[fx]<d[fy]) swap(x,y),swap(fx,fy);
modify(1,1,cnt,id[fx],id[x],1);
x=fa[fx],fx=top[x];
}
if(id[x]>id[y]) swap(x,y);
modify(1,1,cnt,id[x],id[y],1);
}
int main() {
n=qread();
for(int i=1;i<=n;++i) w[i]=qread();
for(int i=1,u,v;i<n;++i) {
u=qread(),v=qread();
ct(u,v);ct(v,u);
}
dfs1(1),dfs2(1,1);
int now=w[1];
for(int i=2;i<=n;++i) {
cal(now,w[i]);
now=w[i];
modify(1,1,cnt,id[now],id[now],-1);
}
for(int i=1;i<=n;++i) printf("%d\n",query(1,1,cnt,id[i]));
return 0;
}