题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3631
Description
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一 的。天哪,他居然真的住在“树”上。松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,……, 最后到an,去参观新家。
可是这样会导致**重复走很多房间,懒惰的**不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。**是个馋家伙,立马就答应了。
现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。
Input
第一行一个整数n,表示房间个数
第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
Output
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。
Sample Input
5
1 4 5 3 2
1 2
2 4
2 3
4 5
1 4 5 3 2
1 2
2 4
2 3
4 5
Sample Output
1
2
1
2
1
2
1
2
1
HINT
2<= n <=300000
题解:
题目要求的是给定一个路径,经过每个点的次数。然后树链剖分,先是两个dfs,第一个dfs求出:子树大*(siz[]),父亲(fa[]),重儿子(son[]),深度(dep[])。第二个dfs求出:所在链的顶端节点(top[]),dfs序中的编号(w[])。一开始看到区间修改会产生用线段树的冲动,但是因为只有到了最后才会需要查询一下,所以可以查分。然后因为除了第一个节点外,从其他每一个节点出发不需要糖果,因为每个点总是在进来的时候已经给了糖果了,所以都要减去一个1,因为终点不用给糖果,所以终点也减去个1
代码:
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define N 300010 using namespace std; int n,p,q,sum,tot; int siz[N],fa[N],son[N],top[N],dep[N],w[N]; int head[N],to[2*N],data[2*N],next[2*N]; int a[N],ans[N]; int getint() { int res=0,w=1; char ch=getchar(); while ((ch>'9' || ch<'0')&&ch!='-') ch=getchar(); if (ch=='-') w=-1,ch=getchar(); while (ch>='0'&&ch<='9') res=res*10+ch-'0',ch=getchar(); return res*w; } void link(int x,int y) {next[++sum]=head[x]; head[x]=sum; to[sum]=y;} void dfs1(int p,int Fa) { siz[p]=1; for (int i=head[p];i;i=next[i]) { if (to[i]!=Fa) { fa[to[i]]=p; dep[to[i]]=dep[p]+1; dfs1(to[i],p); siz[p]+=siz[to[i]]; if (siz[to[i]]>siz[son[p]]) son[p]=to[i]; } } } void dfs2(int p,int t) { top[p]=t; w[p]=++tot; if (son[p]) dfs2(son[p],t); for (int i=head[p];i;i=next[i]) if (to[i]!=fa[p]&&to[i]!=son[p]) dfs2(to[i],to[i]); } void jia(int x,int y) {ans[x]++; ans[y+1]--;} void find(int p,int q) { while (top[p]!=top[q]) { if (dep[top[p]]<dep[top[q]]) swap(p,q); jia(w[top[p]],w[p]); p=fa[top[p]]; } if (dep[p]>dep[q]) swap(p,q); jia(w[p],w[q]); } int main() { n=getint(); for (int i=1;i<=n;i++) a[i]=getint(); for (int i=1;i<=n-1;i++) { p=getint(); q=getint(); link(p,q); link(q,p); } dfs1(1,0); dfs2(1,1); for (int i=1;i<n;i++) find(a[i],a[i+1]); for (int i=1;i<=n;i++) ans[i]+=ans[i-1]; for (int i=1;i<=n;i++) { if (i==a[1]) printf("%d ",ans[w[i]]); else printf("%d ",ans[w[i]]-1); } return 0; }