题解:本题主要考查树链剖分。
简要题意:一颗树,有n个房间,并且有n-1根树枝连接。小熊维尼先去
a
1
a_1
a1,再去
a
2
a_2
a2最后到
a
n
a_n
an,每走到一个房间,他就可以从房间拿一块糖果吃,最后一个房间不用,求每个房间至少需要放多少个糖果。
1.树链剖分:路过的点都加一,可以想到树链剖分,每一次将
a
[
i
]
a[i]
a[i]到
a
[
i
+
1
]
a[i+1]
a[i+1]的节点加一,在一次修改后,因为最后一个房间不用加,所以避免重复终点要减1。线段树模板区间加和区间查询。代码还是比较清楚的。
注意:本题数据较大,要用高效的读写(一般做这些题都要吧QwQ),数组一定要开四倍!
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
struct N
{
int ans,lazy;
}t[1126666];
struct E
{
int start,to;
}e[1266666];
int a[1266666],h[1266666],siz[1266666],son[1266666],d[1266666];
int id[1266666],rk[1266666],top[1266666],f[1266666];
int P,num,n,m;
void pushup(int p)
{
t[p].ans=t[p*2].ans+t[p*2+1].ans;
return ;
}
void build(int p,int l,int r)
{
if(l==r){t[p].ans=a[l];return ;}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void lai(int p,int l,int r)
{
int mid=l+r>>1;
if(t[p].lazy)
{
t[p*2].ans+=t[p].lazy*(mid-l+1);
t[p*2+1].ans+=t[p].lazy*(r-mid);
t[p*2].lazy+=t[p].lazy;
t[p*2+1].lazy+=t[p].lazy;
t[p].lazy=0;
}
return ;
}
void change(int p,int l,int r,int x,int y,int z)
{
if(x<=l&&y>=r)
{
t[p].ans+=z*(r-l+1);
t[p].lazy+=z;
return ;
}
lai(p,l,r);
int mid=l+r>>1;
if(x<=mid)change(p<<1,l,mid,x,y,z);
if(y>mid)change(p<<1|1,mid+1,r,x,y,z);
pushup(p);
}
long long ask(int p,int l,int r,int x,int y)
{
long long ans=0;
if(x<=l&&y>=r)return t[p].ans;
lai(p,l,r);
int mid=l+r>>1;
if(x<=mid)ans+=ask(p<<1,l,mid,x,y);
if(y>mid)ans+=ask(p<<1|1,mid+1,r,x,y);
return ans;
}
void add(int start,int to)
{
e[++P].to=to;
e[P].start=h[start];
h[start]=P;
}
void dfs1(int p,int fa,int deep)
{
f[p]=fa;siz[p]=1;d[p]=deep;
for(int i=h[p];i;i=e[i].start)
{
int k=e[i].to;
if(k==fa)continue;
dfs1(k,p,deep+1);
siz[p]+=siz[k];
if(siz[k]>siz[son[p]])son[p]=k;
}
}
void dfs2(int p,int tp)
{
id[p]=++num;rk[num]=a[p];top[p]=tp;
if(!son[p])return;
dfs2(son[p],tp);
for(int i=h[p];i;i=e[i].start)
{
int k=e[i].to;
if(k==f[p]||k==son[p]) continue;
dfs2(k,k);
}
}
int sum(int x,int y,int z)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])swap(x,y);
change(1,1,n,id[top[x]],id[x],z);
x=f[top[x]];
}
if(d[x]>d[y])swap(x,y);
change(1,1,n,id[x],id[y],z);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
//build(1,1,n);
dfs1(1,0,1);dfs2(1,1);
for(int i=1;i<=n-1;i++)
{
sum(a[i],a[i+1],1);
sum(a[i+1],a[i+1],-1);
}
for(int i=1;i<=n;i++)
printf("%d\n",ask(1,1,n,id[i],id[i]));
return 0;
}