【试炼场】松鼠的新家 【树上差分】

xiaoxiao2025-11-20  11

传送门

题目描述

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,…,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

输入输出格式

输入格式:

第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an

接下来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<= n <=300000

题解

一向话多的我不知道说些什么 读一读题,我们可以发现,实际上他就是给了你几条路经,让你求每个点被经过了多少次。由于是按照最短路径走的,那肯定又是u—>lca(u,v)—>v。

既然如此,这不就是点差分嘛,树上差分一波就搞完了啊。就稍微注意一下,上一条路径的终点是这一次路径的起点,也就是说除了起点和终点以外所有的点都只经过了一次。我看题解区有人是在差分的时候加了判断,但其实没必要啊,只要在输出的时候除了起点终点之外的答案-1就好了。

emm……实在没话说了。不知道为什么树上差分的板子题会是紫色的

代码:(不开O2有个点会T,估计是树剖常数大了,用倍增也许就好了)

#include<bits/stdc++.h> #define rint register int #define endll '\n' #define ivoid inline void #define iint inline int #define ll long long using namespace std; const int N=1e6+5; const int M=2005; const int inf=0x3f3f3f3f; int a,b,head[N],pre,n,m,k,cnt,mx=-inf; struct Edge{ int v; int next; }edge[N]; ll rad() { ll ret=0,f=1; char c; while((c<'0'||c>'9')&&c!='-')c=getchar(); if(c=='-')c=getchar(),f=-1; while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+c-'0',c=getchar(); return ret*f; } ivoid addedge(int u,int v) { edge[++cnt]=(Edge){v,head[u]},head[u]=cnt; } int fa[N],deep[N],size[N],son[N],top[N],val[N],pos[N]; ivoid dfs1(int x) { size[x]=1; for(rint i=head[x],d;i;i=edge[i].next){ d=edge[i].v; if(d==fa[x])continue; fa[d]=x,deep[d]=deep[x]+1; dfs1(d); size[x]+=size[d]; if(size[son[x]]<size[d])son[x]=d; } } ivoid dfs2(int x,int op) { top[x]=op; if(!son[x])return; dfs2(son[x],op); for(rint i=head[x],d;i;i=edge[i].next){ d=edge[i].v; if(d==son[x]||fa[x]==d)continue; dfs2(d,d); } } ivoid dfs3(int x) { for(rint i=head[x],d;i;i=edge[i].next){ d=edge[i].v; if(d==fa[x])continue; dfs3(d); val[x]+=val[d]; } } iint Lca(int x,int y) { while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]])swap(x,y); x=fa[top[x]]; } if(x==y) return x; if(deep[x]>deep[y]) return y; else return x; } ivoid pass(int x,int y) { val[x]++; val[y]++; val[Lca(x,y)]--; val[fa[Lca(x,y)]]--; } int main() { n=rad(); for(rint i=1;i<=n;i++){pos[i]=rad();} for(rint i=1;i<=n-1;i++){ a=rad(),b=rad(); addedge(a,b); addedge(b,a); } dfs1(1); dfs2(1,1); for(rint i=1;i<=n-1;i++){ pass(pos[i],pos[i+1]); } dfs3(1); for(rint i=1;i<=n;i++) if(i!=pos[1]) cout<<val[i]-1<<endll; else if(i!=pos[n]) cout<<val[i]<<endll; else cout<<0<<endll; return 0; }
转载请注明原文地址: https://www.6miu.com/read-5039968.html

最新回复(0)