题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入格式
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
输出格式
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
输入输出样例
输入:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
输出:
1
2
1
2
1
说明/提示
2<= n <=300000
题解
树链剖分模板题
很显然在a[i]->a[i+1]这条路径上直接+1,同时a[i+1]这个点-1
该查询查询 完事
代码
#include <cstdio>
#define ll long long
#define ls(x) x<<1
#define rs(x) x<<1|1
using namespace std;
inline int read(){
int x = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') { if (c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
return x * f;
}
const int maxn=1e6+10;
struct edge{
int next,to;
}e[2*maxn];
struct Node{
int l,r,v,lz;
}t[4*maxn];
int head[maxn],n,m,w[maxn],a[maxn];
int d[maxn],f[maxn],sz[maxn],son[maxn];
int top[maxn],id[maxn],cnt,tot;
inline void swap(int &a,int &b) {int t=a;a=b;b=t;}
inline void add(int x,int y){
e[++cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt;
}
inline void pushup(int x) {t[x].v=t[ls(x)].v+t[rs(x)].v;}
inline void build(int i,int l,int r){
t[i].l=l,t[i].r=r;
if (l==r){
t[i].v=0;
return;
}
int m=(l+r)>>1;
build(ls(i),l,m);
build(rs(i),m+1,r);
pushup(i);
}
inline void pushdown(int k){
t[ls(k)].v=t[ls(k)].v+t[k].lz*(t[ls(k)].r-t[ls(k)].l+1);
t[rs(k)].v=t[rs(k)].v+t[k].lz*(t[rs(k)].r-t[rs(k)].l+1);
t[ls(k)].lz=t[ls(k)].lz+t[k].lz,t[rs(k)].lz=t[rs(k)].lz+t[k].lz;
t[k].lz=0;
}
inline void update(int k,int l,int r,int c){
if (t[k].l>r||t[k].r<l) return;
if (l<=t[k].l&&t[k].r<=r){
t[k].v=t[k].v+(t[k].r-t[k].l+1)*c;
t[k].lz=t[k].lz+c;
return;
}
if (t[k].lz) pushdown(k);
update(ls(k),l,r,c);
update(rs(k),l,r,c);
pushup(k);
}
inline ll query(int k,int l,int r){
if (t[k].l>r||t[k].r<l) return 0;
if (l<=t[k].l&&t[k].r<=r) return t[k].v;
if (t[k].lz) pushdown(k);
ll sum=0;
sum=sum+query(ls(k),l,r);
sum=sum+query(rs(k),l,r);
return sum;
}
inline void dfs1(int u,int fa,int depth){
f[u]=fa;
d[u]=depth;
sz[u]=1;
for (int i=head[u];i;i=e[i].next){
int v=e[i].to;
if (v==fa) continue;
dfs1(v,u,depth+1);
sz[u]+=sz[v];
if (sz[v]>sz[son[u]]) son[u]=v;
}
}
inline void dfs2(int u,int t){
top[u]=t;
id[u]=++tot;
if (!son[u]) return;
dfs2(son[u],t);
for (int i=head[u];i;i=e[i].next){
int v=e[i].to;
if (v!=son[u]&&v!=f[u]) dfs2(v,v);
}
}
inline ll query_path(int x,int y){
ll ans=0;
while (top[x]!=top[y]){
if (d[top[x]]<d[top[y]]) swap(x,y);
ans+=query(1,id[top[x]],id[x]);
x=f[top[x]];
}
if (id[x]>id[y]) swap(x,y);
ans+=query(1,id[x],id[y]);
return ans;
}
inline void update_path(int x,int y,int k){
while (top[x]!=top[y]){
if (d[top[x]]<d[top[y]]) swap(x,y);
update(1,id[top[x]],id[x],k);
x=f[top[x]];
}
if (id[x]>id[y]) swap(x,y);
update(1,id[x],id[y],k);
}
void work(){
n=read();
for (int i=1;i<=n;i++) a[i]=read();
for (int i=1;i<n;i++) {int a=read(),b=read();add(a,b),add(b,a);}
dfs1(1,0,1);
dfs2(1,1);
build(1,1,n);
for (int i=1;i<n;++i){
update_path(a[i],a[i+1],1);
update_path(a[i+1],a[i+1],-1);
}
for (int i=1;i<=n;++i) printf("%d\n",query(1,id[i],id[i]));
}
int main(){
work();
return 0;
}