bzoj 3631: [JLOI2014]松鼠的新家

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


树链剖分的题目在win下跑总是爆栈导致没法debug..比较怨念。只能换到lemon下加编译命令测。

这题可以先树链剖分,然后路径区间加即可了。

#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct line
{
     int s,t;
     int next;
}a[600001];
int edge;
int head[300001];
inline void add(int s,int t)
{
	 a[edge].next=head[s];
     head[s]=edge;
     a[edge].s=s;
     a[edge].t=t;
}
struct tree
{
     int l,r;
     int s;
     int tag;
}tr[1200001];
inline int max(int x,int y)
{
     if(x>y)
          return x;
     return y;
}
inline void up(int p)
{
     tr[p].s=tr[p*2].s+tr[p*2+1].s;
}
inline void down(int p)
{
	 int l=tr[p].r-tr[p].l+1;
	 tr[p*2].s+=(l-l/2)*tr[p].tag;
	 tr[p*2+1].s+=l/2*tr[p].tag;
     tr[p*2].tag+=tr[p].tag;
     tr[p*2+1].tag+=tr[p].tag;
     tr[p].tag=0;
}
inline void build(int p,int l,int r)
{
     tr[p].l=l;
     tr[p].r=r;
     if(l!=r)
     {
          int mid=(l+r)/2;
          build(p*2,l,mid);
          build(p*2+1,mid+1,r);
     }
}
inline void change(int p,int l,int r,int x)//单点修改 l==r 故未加tag操作 
{
     if(l<=tr[p].l&&tr[p].r<=r)
     {
          tr[p].s+=(tr[p].r-tr[p].l+1)*x;
          tr[p].tag+=x;
     }
     else
     {
     	  down(p);
	      int mid=(tr[p].l+tr[p].r)/2;
		  if(l<=mid)
		       change(p*2,l,r,x);
		  if(r>mid)
		       change(p*2+1,l,r,x);
		  up(p);
     }
}
inline int find(int p,int l,int r)
{
     if(l<=tr[p].l&&tr[p].r<=r)
          return tr[p].s;
     else
     {
     	  down(p);
	      int mid=(tr[p].l+tr[p].r)/2;
	      int ans=0;
		  if(l<=mid)
		       ans+=find(p*2,l,r);
		  if(r>mid)
		       ans+=find(p*2+1,l,r);
		  return ans;
     }
}
int dep[300001],size[300001],son[300001],fa[300001];
int top[300001],w[300001];
int lson[300001]/*最大节点位置*/,mson[300001]/*最大节点值*/;
int tot;
inline void dfs1(int d)
{
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
     	  int t=a[i].t;
          if(t!=fa[d])
          {
          	   dep[t]=dep[d]+1;
               fa[t]=d;
               dfs1(t);
               son[d]+=son[t]+1;
               if(son[t]>=mson[d])
               {
                    mson[d]=son[t];
                    lson[d]=t;
               }
          }
     }
}
inline void dfs2(int d)
{
     int i;
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t==lson[d])
          {
               top[t]=top[d];
               tot++;
               w[t]=tot;
               dfs2(t);
          }
     }
     for(i=head[d];i!=0;i=a[i].next)
     {
          int t=a[i].t;
          if(t!=fa[d]&&t!=lson[d])
          {
               top[t]=t;
               tot++;
               w[t]=tot;
               dfs2(t);
          }
     }
}
inline void addx(int s,int t)
{
	 int u=top[s],v=top[t];
     while(u!=v)
     {
          if(dep[u]>dep[v])
          {
          	   change(1,w[u],w[s],1);
               s=fa[top[s]];
          }
          else
          {
          	   change(1,w[v],w[t],1);
               t=fa[top[t]];
          }
          u=top[s];
          v=top[t];
     }
     if(w[s]<w[t])
          change(1,w[s],w[t],1);
     else
          change(1,w[t],w[s],1);
}
int val[300001];
int main()
{
//     freopen("home.in","r",stdin);
//     freopen("home.out","w",stdout);
     int n;
     scanf("%d",&n);
     int i,s,t;
     for(i=1;i<=n;i++)
          scanf("%d",&val[i]);
     for(i=1;i<=n-1;i++)
     {
          scanf("%d%d",&s,&t);
          edge++;
          add(s,t);
          edge++;
          add(t,s);
     }
     dep[1]=1;
     dfs1(1);
     top[1]=1;
     tot++;
     w[1]=tot;
     dfs2(1);
     build(1,1,n);
     for(i=1;i<=n-1;i++)
     {
          addx(val[i],val[i+1]);
          if(i!=1)
               change(1,w[val[i]],w[val[i]],-1);
     }
     change(1,w[val[n]],w[val[n]],-1);
     for(i=1;i<=n;i++)
          printf("%d\n",find(1,w[i],w[i]));
     return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值