[JLOI 2014]松鼠的新家

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

题解

裸的树上差分。

我们将一条路径如$u->v$,

我们需要将标记数组:

$$cnt[u]++,cnt[v]++,cnt[lca(u,v)]--,cnt[fa[lca(u,v)][0]]--$$

最后上传标记即可,正确性可以画图推一下。

但注意由于这样做会将每个点重复计算一次(上一条路径的结尾,这一条路径的起始)

我们需要将每个点点权再$-1$,

注意由于第一条路径起始点是要计算的,我们还要加回来。

  1 #include<set>
  2 #include<map>
  3 #include<ctime>
  4 #include<cmath>
  5 #include<queue>
  6 #include<stack>
  7 #include<vector>
  8 #include<cstdio>
  9 #include<string>
 10 #include<cstring>
 11 #include<cstdlib>
 12 #include<iostream>
 13 #include<algorithm>
 14 #define LL long long
 15 #define Max(a,b) ((a)>(b) ? (a):(b))
 16 #define Min(a,b) ((a)<(b) ? (a):(b))
 17 using namespace std;
 18 const int N=300000;
 19 
 20 int n,u,v,lim;
 21 struct tt
 22 {
 23     int to,next;
 24 }edge[N*2+5];
 25 int path[N+5],top;
 26 void Add(int u,int v);
 27 int a[N+5];
 28 
 29 int dep[N+5],fa[N+5][20];
 30 void Dfs(int r,int depth);
 31 void RMQ();
 32 int lca(int a,int b);
 33 
 34 int cnt[N+5];
 35 void Dfs2(int r);
 36 
 37 int main()
 38 {
 39     scanf("%d",&n);
 40     lim=log(n)/log(2);
 41     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 42     for (int i=1;i<n;i++)
 43     {
 44       scanf("%d%d",&u,&v);
 45       Add(u,v);
 46       Add(v,u);
 47     }
 48     Dfs(1,1);
 49     RMQ();
 50     for (int i=1;i<n;i++)
 51     {
 52       int w=lca(a[i],a[i+1]);
 53       cnt[a[i]]++,cnt[a[i+1]]++,cnt[w]--,cnt[fa[w][0]]--;
 54     }
 55     Dfs2(1);
 56     cnt[a[1]]++;
 57     for (int i=1;i<=n;i++) printf("%d
",cnt[i]-1);
 58     return 0;
 59 }
 60 
 61 void Add(int u,int v)
 62 {
 63     edge[++top].to=v;
 64     edge[top].next=path[u];
 65     path[u]=top;
 66 }
 67 void Dfs(int r,int depth)
 68 {
 69     dep[r]=depth;
 70     for (int i=path[r];i;i=edge[i].next)
 71       if (!dep[edge[i].to])
 72       {
 73           fa[edge[i].to][0]=r;
 74           Dfs(edge[i].to,depth+1);
 75       }
 76 }
 77 void RMQ()
 78 {
 79     for (int t=1;t<=lim;t++)
 80       for (int i=1;i<=n;i++)
 81           fa[i][t]=fa[fa[i][t-1]][t-1];
 82 }
 83 int lca(int a,int b)
 84 {
 85     if (dep[a]<dep[b]) swap(a,b);
 86     for (int i=lim;i>=0;i--) if (dep[fa[a][i]]>=dep[b]) a=fa[a][i];
 87     if (a!=b)
 88     {
 89       for (int i=lim;i>=0;i--) if (fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i];
 90       a=fa[a][0],b=fa[b][0];
 91     }
 92     return a;
 93 }
 94 void Dfs2(int r)
 95 {
 96     for (int i=path[r];i;i=edge[i].next)
 97     if (edge[i].to!=fa[r][0])
 98     {
 99         Dfs2(edge[i].to);
100         cnt[r]+=cnt[edge[i].to];
101     }
102 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/7449095.html