题目描述
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有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 ",(ans+1)/2); 47 } 48 }