[树上差分][lca] Luogu P3258 松鼠的新家

Posted comfortable

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[树上差分][lca] Luogu P3258 松鼠的新家相关的知识,希望对你有一定的参考价值。

题目描述

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

松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,......,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

 

题解

  • 就是一道比较裸的树上差分题目

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #define N 300010
 5 using namespace std;
 6 struct edge int to,from,v; e[N*2];
 7 int n,cnt,head[N],f[40][N],deep[N],a[N],cf[N],vis[N];
 8 void insert(int x,int y)
 9 
10     e[++cnt].to=y,e[cnt].from=head[x],head[x]=cnt;
11     e[++cnt].to=x,e[cnt].from=head[y],head[y]=cnt;
12 
13 int lca(int x,int y)
14 
15     if (deep[x]<deep[y]) swap(x,y);
16     for (int i=30;i>=0;i--) if (deep[f[i][x]]>=deep[y]) x=f[i][x];
17     if (x==y) return x;
18     for (int i=30;i>=0;i--) if (f[i][x]!=f[i][y]) x=f[i][x],y=f[i][y];
19     return f[0][x];
20 
21 void dfs(int x,int fa)
22 
23     f[0][x]=fa,deep[x]=deep[fa]+1;
24     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa) dfs(e[i].to,x);
25 
26 int dfs1(int x)
27 
28     int ans=cf[x]; vis[x]=1;
29     for (int i=head[x];i;i=e[i].from) if (!vis[e[i].to]) ans+=(e[i].v=dfs1(e[i].to));
30     for (int i=head[x];i;i=e[i].from) if (e[i].to==f[0][x]) e[i].v=ans,i=0;
31     return ans;
32 
33 int main()
34 
35     scanf("%d",&n);
36     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
37     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y);
38     dfs(a[1],a[1]);
39     for (int i=1;(1<<i)<=n;i++) for (int j=1;j<=n;j++) f[i][j]=f[i-1][f[i-1][j]];
40     for (int i=1;i<n;i++)  cf[a[i]]++,cf[a[i+1]]++,cf[lca(a[i],a[i+1])]-=2;
41     memset(vis,0,sizeof(vis)),dfs1(a[1]);
42     for (int i=1;i<=n;i++)
43     
44         int ans=0;
45         for (int j=head[i];j;j=e[j].from) ans+=e[j].v;
46         if (i==a[n]) ans--; printf("%d\n",(ans+1)/2);
47     
48 

 

以上是关于[树上差分][lca] Luogu P3258 松鼠的新家的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P1600 天天爱跑步 树上差分

luogu P1600 天天爱跑步 |树上差分+LCA

洛谷P3258松鼠的新家

洛谷 [P3258] 松鼠的新家

松鼠的新家 (lca+树上差分)或(树链剖分)

NOIp2015 运输计划 [LCA] [树上差分] [二分答案]