Description

松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。
可是这样会导致维尼重复走很多房间,懒惰的维尼不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。维尼是个馋家伙,立马就答应了。
现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

Input

第一行一个整数n,表示房间个数
第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。

Output

一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

HINT

2<= n <=300000

  这道题一看,这不是要求每次给树上的一条路径权值加一,最后询问每个点的权值。那么这就是树剖的板子题了,套个树状数组即可。

  然而,由于这道题只在最后有一个询问操作,那么树链剖分未免有点大材小用了。我们可以维护一个数组$b$,每次给$b_i$加上$x$就表示给从$i$到根的路径上所有节点的权值都加上$x$。这样,我们只需在最后$dfs$一遍,把值自底往上加即可得到权值数组。这样的话,每次给路径$(u,v)$上的点全部加一对应需要改变$b$数组中四个值:$b_u+1$,$b_v+1$,$lca(u,v)-1$,$fa(lca(u,v))-1$即可。这样我们修改的复杂度就极大地降低了。

  然后,我一开始写了一个倍增求$lca$,后来发现其他人都跑得比我快……自己想了想,还是决定写个$Tarjan$求$lca$算了,毕竟以前没有写过……后来发现这真的好写,不比倍增难写……

  $Tarjan$求$lca$大概的思路就是在$dfs$的时候,维护一个并查集,对已经$dfs$完了的点在并查集中指向它的$father$,正在栈中的点指向它自己。这样的话,每到一个点$u$,我们可以扫一遍所有的$(u,v)$这种询问,如果$v$被访问过了,那么这个询问的答案就是并查集中$v$的树根。感觉这个自己$YY$一下不难证明,这里就不证明了。

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 300010
#define maxm 600010 using namespace std;
typedef long long llg; struct data{
int u,v;
}s[maxm];
int head[maxn],next[maxm],to[maxm],tt;
int he[maxn],ne[maxm],t1[maxm],t2;
int n,ans[maxn],fa[maxn],a[maxn],ff[maxn],b[maxn]; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} int find(int x){return fa[fa[x]]==fa[x]?fa[x]:fa[x]=find(fa[x]);}
void lik(int x,int y){t1[++t2]=y;ne[t2]=he[x];he[x]=t2;}
void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
} void dfs(int u,int f){
fa[u]=u; ff[u]=f;
for(int i=he[u],v;v=t1[i],i;i=ne[i])
if(fa[s[v].v]) ans[(v-1)%(n-1)+1]=find(s[v].v);
for(int i=head[u],v;v=to[i],i;i=next[i])
if(v!=f) dfs(v,u);
fa[u]=f;
} void dfs(int u){
for(int i=head[u],v;v=to[i],i;i=next[i])
if(v!=ff[u]) dfs(v),b[u]+=b[v];
} int main(){
File("a");
n=getint();
for(int i=1;i<=n;i++) a[i]=getint();
for(int i=1;i<n;i++){
s[i].u=s[i+n-1].v=a[i]; lik(s[i].u,i);
s[i].v=s[i+n-1].u=a[i+1]; lik(s[i].v,i+n-1);
}
for(int i=2;i<=n;i++) link(getint(),getint());
dfs(1,0);
for(int i=1;i<n;i++){
b[s[i].u]++; b[ff[s[i].v]]++;
b[ans[i]]--; b[ff[ans[i]]]--;
}
dfs(1);
for(int i=1;i<=n;i++) printf("%d\n",b[i]);
return 0;
}

BZOJ 3631 【JLOI2014】 松鼠的新家的更多相关文章

  1. BZOJ 3631: [JLOI2014]松鼠的新家( 树链剖分 )

    裸树链剖分... ------------------------------------------------------------------- #include<bits/stdc++ ...

  2. Bzoj 3631: [JLOI2014]松鼠的新家(树链剖分+线段树)

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec Memory Limit: 128 MB Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个 ...

  3. bzoj 3631: [JLOI2014]松鼠的新家

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树&q ...

  4. 洛谷 P3258 BZOJ 3631 [JLOI2014]松鼠的新家

    题目描述 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前 ...

  5. BZOJ 3631: [JLOI2014]松鼠的新家 树上差分 + LCA

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在“树”上.松鼠想邀 ...

  6. BZOJ.3631.[JLOI2014]松鼠的新家(树上差分)

    题目链接 树剖/差分裸题.. //28260kb 584ms #include <cstdio> #include <cctype> #include <algorith ...

  7. 3631: [JLOI2014]松鼠的新家

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 707  Solved: 342[Submit][Statu ...

  8. 3631. [JLOI2014]松鼠的新家【树形DP】

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在“树”上.松鼠想邀 ...

  9. [Bzoj3631][JLOI2014]松鼠的新家 (树上前缀和)

    3631: [JLOI2014]松鼠的新家 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2350  Solved: 1212[Submit][Sta ...

  10. [填坑]树上差分 例题:[JLOI2014]松鼠的新家(LCA)

    今天算是把LCA这个坑填上了一点点,又复习(其实是预习)了一下树上差分.其实普通的差分我还是会的,树上的嘛,也是懂原理的就是没怎么打过. 我们先来把树上差分能做到的看一下: 1.找所有路径公共覆盖的边 ...

随机推荐

  1. UI控件(复习一下)

    如何修改控件状态• 可见,确实需要经常修改控件状态• 那如何去修改控件的状态呢?方法很简单➢ 每一个UI控件都是一个对象➢ 修改UI控件的状态,其实就是修改控件对象的属性➢ 比如修改UILabel显示 ...

  2. c中的基本运算

    一. 算术运算 C语言一共有34种运算符,包括了常见的加减乘除运算 1. 加法运算+ l 除开能做加法运算,还能表示正号:+5.+90 2. 减法运算- l 除开能做减法运算,还能表示符号:-10.- ...

  3. Sql server profiler抓出的语句不可信

      Sql profiler抓出的语句不可信      

  4. 基于ZooKeeper的Dubbo注册中心

    SOA服务治理 dubbo_zk 服务总线 感兴趣的M我微信:wonter 微信扫描,人人 CTO 大本营 基于SOA架构的TDD测试驱动开发模式 服务治理要先于SOA 简述我的SOA服务治理 从页面 ...

  5. js中的==运算: [''] == false —>true

    图1 计算下面表达式的值: [''] == false 首先,两个操作数分别是对象类型.布尔类型.根据图1,需要将布尔类型转为数字类型,而false转为数字的结果是0,所以表达式变为: [''] == ...

  6. Javascript之旅——第三站:几个需要注意的运算符

    平时写惯了C#,所以会觉得什么样的运算符就应该做什么样的运算,但是有一天你的习惯被其他语言颠覆了,不知道是不是有一股强大的好奇 心,刚好在js中,我的这种习惯就被颠覆了,下面就看看哪些运算符颠覆了我的 ...

  7. SQL Server:统计数据库中每张表的大小

    1. 统计数据库中每张表的大小 1.1 首先执行下面的命令 exec sp_MSforeachtable @command1="sp_spaceused '?'"; 1.2 检测当 ...

  8. Angularjs之如何在跨域请求中传输Cookie

    一般情况我们在使用WebApi之类的技术时,都会遇到跨域的问题,这个只需要在服务端做一下处理即可. 如果这些GET或POST请求不需要传递Cookie数据的话,就没什么问题了,但如果需要,那么会发现 ...

  9. Linux 性能优化工具包 sysstat 以及 sysstat 服务

    1. sysstat service 1.1. /etc/cron.d/sysstat Linux 下的性能分析,少不了要使用 sysstat 工具包中的命令.同时 sysstat 服务会自动每个10 ...

  10. Android ImageView(scaleType属性)(转)

    (转自:http://www.open-open.com/lib/view/open1378257991687.html) <ImageView android:id="@+id/im ...