[JLOI2014]松鼠的新家

来源:互联网 发布:小学生学英语单词软件 编辑:程序博客网 时间:2024/04/25 21:21

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

30%的数据,n<=4000

80%的数据,n<=50000

100%的数据,2<= n <=300000

Source

JLOI2014

#include<stdio.h>
int a[300001];
int f[300001][21];
int level[300001];
int ans[300001][50];
int queue[300001];
int to[600001];
int next[600001];//边开2倍,双向边
int head[300001];
int fa[300001];
int sum,tmp;
void addedge(int a,int b)//链表加边
{
    next[++sum]=head[a];
    head[a]=sum;
    to[sum]=b;
}
void dfs(int x)
{
    for(int i=1;i<=18;i++)
    {
        if(level[x]>=(1<<i))
             f[x][i]=f[f[x][i-1]][i-1];
        else
            break;
    }
    for(int i=head[x];i;i=next[i])
     {
        if(to[i]==f[x][0])
            continue;
         level[to[i]]=level[x]+1;
         f[to[i]][0]=x;
         dfs(to[i]);
     }    
}
int lca(int a,int b)
{
    if(level[a]<level[b])
        tmp=a,a=b,b=tmp;
    int deep=level[a]-level[b];
    /*if(a==b)
        return a;*/
    for(int i=0;i<19;i++)
    {
        if((deep&(1<<i))!=0)
            a=f[a][i];
    }
    /*if(a==b)
        return a;*/
    for(int j=18;j>=0;j--)
    {
        if(f[a][j]!=f[b][j])
            a=f[a][j],b=f[b][j];
    }
    if(a==b)
        return a;//和上面一样.
    return f[a][0];
}
void dfs2(int x)
{
    for(int j=head[x];j;j=next[j])//注意,j=next[x];
    {
        if(to[j]==f[x][0])
            continue;
        dfs2(to[j]);
        fa[x]+=fa[to[j]];
    }
}
int main()
{
    int n,c,b;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&c,&b);
        addedge(c,b);
        addedge(b,c);
    }
    dfs(a[1]);//以1为树根寻找
    for(int i=1;i<n;i++)
    {
        int father=lca(a[i],a[i+1]);
        //printf("%d\n",father);
        fa[a[i]]++,fa[a[i+1]]++;
        fa[father]--;
        fa[f[father][0]]--;//差分数组修改
    }
    dfs2(a[1]);
    for(int i=2;i<=n;i++)
        fa[a[i]]--;
    for(int i=1;i<=n;i++)
        printf("%d\n",fa[i]);
}


原创粉丝点击