【Bzoj3631】松鼠的新家

来源:互联网 发布:淘宝珍珠项链 编辑:程序博客网 时间:2024/03/29 01:18

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[n]都要减一。为什么呐......嘿嘿嘿,不告诉你。


------------------------------------------我是一条萌萌哒的分割线>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;}


话说松鼠和熊的故事中是不是还少了个...光头...??!


0 0
原创粉丝点击