bzoj3631:[JLOI2014]松鼠的新家

题目链接: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

Sample Output

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\n",ans[w[i]]);
            else printf("%d\n",ans[w[i]]-1);
        }
    return 0;
}

 

posted @ 2016-10-20 15:27  xiaoqiang200015  阅读(156)  评论(0编辑  收藏  举报