题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有nnn 个房间,并且有 n−1n-1n−1 根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。
松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去 a1a_1a1,再去 a2a_2a2,……,最后到 ana_nan,去参观新家。可是这样会导致**重复走很多房间,懒惰的**不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
**是个馋家伙,立马就答应了。现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间 ana_nan 是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入格式
第一行一个正整数 nnn,表示房间个数第二行 nnn 个正整数,依次描述 a1,a2,⋯ ,ana_1, a_2,\cdots,a_na1,a2,⋯,an。
接下来 n−1n-1n−1 行,每行两个正整数 x,yx,yx,y,表示标号 xxx 和 yyy 的两个房间之间有树枝相连。
输出格式
一共 nnn 行,第 iii 行输出标号为 iii 的房间至少需要放多少个糖果,才能让**有糖果吃。
输入输出样例
输入 #1
5 1 4 5 3 2 1 2 2 4 2 3 4 5
输出 #1
1 2 1 2 1
可能在一些路径上反复经过,所以考虑树上差分(其实是看见tag了
从a走到b,就是相当于给a到b这条路径上的 a ~ b的前一个节点 的糖数++。为什么是前一个结点呢?因为如果不是这样的话b这个节点的糖数会加重复了比如a~b都++,b~c都++,则b相当于重复了一次,不理解的话可以考虑一下到叶子节点时这种特殊的情况,注意题目也在暗示了“当**在参观的最后到达餐厅时就不需要再拿糖果吃了。”
最后跑一遍DFS求出答案即可。
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <cmath> #include <algorithm> using namespace std; const int SIZE=300005; int f[SIZE][22],d[SIZE],vis[SIZE],lg[SIZE]; int ver[SIZE*2],Next[SIZE*2],head[SIZE]; int diff[SIZE]; int go[SIZE]; bool deg[SIZE];//度数,叶子节点度数为1,可以很好的区分 int n,k,tot=0; queue<int>q; int ans=0; void add(int x,int y) { ver[++tot]=y,Next[tot]=head[x],head[x]=tot; } void bfs() { q.push(go[1]),d[go[1]]=1;//? while(q.size()) { int x=q.front();q.pop(); int i; for(i=head[x];i;i=Next[i]) { int y=ver[i]; if(d[y])continue; d[y]=d[x]+1; f[y][0]=x; int j; for(j=1;j<=lg[d[x]];j++) { f[y][j]=f[f[y][j-1]][j-1]; } q.push(y); } } } int lca(int x,int y) { if(d[x]<d[y])swap(x,y); while(d[x]>d[y]) { x=f[x][lg[d[x]-d[y]]-1]; } if(x==y)return x; int i; for(i=lg[d[x]]-1;i>=0;i--) { if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; } return f[x][0]; } void dfs(int x,int pre)//统计一遍树上前缀和 { int i; for(i=head[x];i;i=Next[i]) { int y=ver[i]; if(y==pre)continue; dfs(y,x);//此时y已经被更新过了 diff[x]+=diff[y]; } } int main() { cin>>n; int i; memset(deg,0,sizeof(deg)); for(i=1;i<=n;i++)lg[i]=lg[i-1]+(1<<lg[i-1]==i); for(i=1;i<=n;i++)scanf("%d",&go[i]); memset(diff,0,sizeof(diff)); for(i=1;i<=n-1;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y);//反向边 add(y,x); deg[x]++,deg[y]++; } bfs(); for(i=1;i<=n-1;i++) { int x=go[i],y=go[i+1]; int anc=lca(x,y); diff[x]++,diff[f[y][0]]++,diff[anc]--,diff[f[anc][0]]--;//注意是y的前一个节点 } dfs(go[1],0); for(i=1;i<=n;i++)cout<<diff[i]<<endl; return 0; }