[JLOI2014]松鼠的新家

题目描述

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有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

 

 

 

 


题解

  

     可以说是一道树链剖分的模板题吧

     但是注意一下有坑

     

     参观的n 个房间并不一定包括了所有的房间!

     e.g. 参观1->2->1->3->1 

     以及最坏情况需要开long long

 

 


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long 
using namespace std;
const int N=300010;
struct node{
    int to,next;
}e[N<<1];
int dep[N],fa[N],sum[4*N],lazy[4*N],num,head[N],dic[N];
int size[N],son[N],ch[N],now,n,l[N],top[N],tot;
void add(int from,int to)
{
    num++;
    e[num].to=to;
    e[num].next=head[from];
    head[from]=num;
}

void push(int root,int l,int r)
{
    int mid=(l+r)>>1;
    lazy[root<<1]+=lazy[root];
    lazy[root<<1|1]+=lazy[root];
    sum[root<<1]+=lazy[root]*(mid-l+1);
    sum[root<<1|1]+=lazy[root]*(r-mid);
    lazy[root]=0;
    return ;
}

void update(int root,int left,int right,int l,int r,int k)
{
    if(l>right||r<left)return ;
    if(l<=left&&right<=r)
    {
        sum[root]+=k*(right-left+1);
        lazy[root]+=k;
        return ;
    }
    int mid=(left+right)>>1;
    if(lazy[root])push(root,left,right);
    if(mid>=l)update(root<<1,left,mid,l,r,k);
    if(r>mid) update(root<<1|1,mid+1,right,l,r,k);
    sum[root]=sum[root<<1]+sum[root<<1|1];
    return ;
}

ll query(int root,int left,int right,int l,int r)
{
    if(l>right||r<left)return 0;
    if(l<=left&&right<=r)return sum[root];
    int mid=(left+right)>>1;
    if(lazy[root])push(root,left,right);
    ll a=0,b=0;
    if(mid>=l)a=query(root<<1,left,mid,l,r);
    if(mid<r) b=query(root<<1|1,mid+1,right,l,r);
    return a+b;
}

void dfs1(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dep[v])
        {
            dep[v]=dep[x]+1;
            fa[v]=x;
            dfs1(v);
            size[x]+=size[v];
            if(size[v]>size[son[x]])son[x]=v;
        }
    }
    return ;
}

void dfs2(int x,int t)
{
    l[x]=++tot;top[x]=t;
    if(son[x])dfs2(son[x],t);
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa[x]&&v!=son[x])
        {
            dfs2(v,v);
        }
    }
    return ;
}

void cap(int x,int y)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])
        {
            swap(fx,fy);swap(x,y);
        }
        update(1,1,n,l[fx],l[x],1);
        x=fa[fx];
        fx=top[x];
    }
    if(l[x]>l[y])
    swap(x,y);
    update(1,1,n,l[x],l[y],1);
    return ;
}

ll read()
{
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        ch[i]=read();
        if(i!=1)dic[ch[i]]++;
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dep[1]=1;
    fa[1]=0;
    dfs1(1);
    dfs2(1,1);
    
    for(int i=2;i<=n;i++)
    {
        cap(ch[i-1],ch[i]);
    }
    for(int i=1;i<=n;i++)
    {
        cout<<query(1,1,n,l[i],l[i])-dic[i]<<endl;
    }
    return 0;
}

 

posted @ 2018-04-10 16:54  Epiphyllum_thief  阅读(160)  评论(0编辑  收藏  举报