您的位置:首页 > 理论基础 > 数据结构算法

【Bzoj3631】松鼠的新家

2017-02-11 13:58 176 查看

3631: [JLOI2014]松鼠的新家

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 1780  Solved: 865

[Submit][Status][Discuss]

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

两种常见解法:树剖维护线段树,树上差分LCA。这里用的是倍增求LCA之后树上差分的方法,而且效率比一些神方法低,但是理解起来的话还是挺简单的。
a数组的话意思不用多说,但是注意事项的话,要以a[1]而不是1为根,下放标记也以a[1]开始。其他数组应该意思也很明显,主要注意到tmp数组。保存的也就是这个点被访问的次数,我们采用差分的思想,每次经过一条边,(如从u到v)我们让tmp[u]++,tmp[v]++,tmp[LCA(u,v)]--,tmp[grand[LCA(u,v)][0]]--。(最后要把tmp推上去)以一次添加为例想象一下,首先u到根的路径上tmp都+1,此时u到根间结点tmp都为1,之后v到根路径上tmp+1,此时u到LCA前一个,v到LCA前一个点的tmp都+1,而LCA到根的所有点都+2,然后从tmp[LCA]--,更新上去,此时u-v路上所有tmp都+1,已经达到目的。而多余的是什么部分呢,也就是LCA的上一个结点(grand[LCA][0])到根的这一段都多加了1,所以tmp[grand[LCA][0]]--,更新上去,也就完成了。
实际操作时也就不需要每次更新都推上去,只要把四个tmp维护好,最后Dfs走一边就更新完了。但是最后求答案时,a[2]~a
都要减一。为什么呐......嘿嘿嘿,不告诉你。

------------------------------------------我是一条萌萌哒的分割线>w<-------------------------------------------------

咳咳,看在你这么有诚意地翻下来的份上,就告诉你。因为每次的终点就是下一次的起点(结束...也正是新的开始)←不正常。所以这样的话相当于后面的每个房间都多放了一颗,最后一个房间也是一样(所以题目说不用放糖),把它当作多算了一遍减去就好。这题的样例还算良心的,可以对着图推一推吧...看懂意思比较重要。树剖的话...hhhhhhh学会了以后再说吧。

#include <cstdio>
#include <algorithm>

using namespace std;

const int maxx = 300000 + 100;

int head[maxx],next[maxx<<1],to[maxx<<1];
int grand[maxx][20+2],depth[maxx],tmp[maxx],a[maxx];
bool done[maxx];
int n,m,root,x,y,num,size,Ans;

inline int read(){
int x = 0,f = 1;char c = getchar();
while(c>'9'||c<'0') {if(c == '-') f = -1;c = getchar();}
while(c>='0'&&c<='9') {x = x*10+c-'0'; c = getchar();}
return x*f;
}

void Add(int x,int y){
to[++num] = y;
next[num] = head[x];
head[x] = num;
}

void Dfs(int x){
done[x] = true;
for(int i=1;i<=20;i++){
if(depth[x] < (1<<i)) break;
grand[x][i] = grand[grand[x][i-1]][i-1];
}
for(int i=head[x];i;i=next[i]){
int now = to[i];
if(done[now]) continue;
grand[now][0] = x;
depth[now] = depth[x] + 1;
Dfs(now);
}
}

int Lca(int x,int y){
if(depth[x] > depth[y]) x^=y^=x^=y;
int d = depth[y] - depth[x];
for(int i=0;i<=20;i++)
if((1<<i) & d)
y = grand[y][i];
for(int i=20;i>=0;i--)
if(grand[x][i] != grand[y][i])
x = grand[x][i],y = grand[y][i];
return x == y? x : grand[x][0];
}

void pushdown(int x)
{
for(int i=head[x];i;i=next[i])
{
if (to[i]==grand[x][0]) continue;
pushdown(to[i]);
tmp[x]+=tmp[to[i]];
}
}

int main(){
n = read();
for(int i=1;i<=n;i++)
a[i] = read();
for(int i=1;i<n;i++){
x = read();y = read();
Add(x,y);Add(y,x);
}
Dfs(a[1]);
for(int i=1;i<n;i++){
int u = a[i],v = a[i+1];
tmp[u]++;tmp[v]++;
tmp[Lca(u,v)]--;
tmp[grand[Lca(u,v)][0]]--;
}
pushdown(a[1]);
for(int i=2;i<=n;i++)
tmp[a[i]]--;
for(int i=1;i<=n;i++)
printf("%d\n",tmp[i]);
return 0;
}



话说松鼠和熊的故事中是不是还少了个...光头...??!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Bzoj 算法 数据结构 LCA