P3258

[JLOI2014]松鼠的新家

题目描述

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

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

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

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

输入格式

第一行一个正整数 \(n\),表示房间个数第二行 \(n\) 个正整数,依次描述 \(a_1, a_2,\cdots,a_n\)

接下来 \(n-1\) 行,每行两个正整数 \(x,y\),表示标号 \(x\)\(y\) 的两个房间之间有树枝相连。

输出格式

一共 \(n\) 行,第 \(i\) 行输出标号为 \(i\) 的房间至少需要放多少个糖果,才能让小猫有糖果吃。

样例 #1

样例输入 #1

5
1 4 5 3 2
1 2
2 4
2 3
4 5

样例输出 #1

1
2
1
2
1

提示

对于全部的数据,\(2 \le n \le 3 \times 10^5\)\(1 \le a_i \le n\)

LCA+树上差分
由于树上区间加不好用线段树 树状数组 所以用树上差分
对于u~v t=LCA(u,v)
则每次将chafen[t]-- chafen[fa[t][0]]-- chafen[u]++ chafen[v]++
最后dfs累加回来即可 dfs(v,u) chafen[u]+=chafen[v]
LCA倍增不要写挂!
点击查看代码
#include<bits/stdc++.h>//LCA+树上差分 
using namespace std;
int n,chafen[300005];
struct Tree {
	int nxt,to;
} edge[300005*2];
int head[300005*2],cnt,a[300005];
void add(int u,int v) {
	cnt++;
	edge[cnt].nxt=head[u];
	edge[cnt].to=v;
	head[u]=cnt;
}
int lg[300005];
void init() {
	for(int i=1; i<=n; i++)
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
}
int fa[300005][31],dep[300005];
void dfs(int u,int fat) {
	fa[u][0]=fat,dep[u]=dep[fat]+1;
	for(int i=1; i<=lg[dep[u]]; i++)
		fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=head[u]; i; i=edge[i].nxt) {
		int v=edge[i].to;
		if(v==fat)continue;
		dfs(v,u);
	}
}
int LCA(int x,int y) {
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])
		x=fa[x][lg[dep[x]-dep[y]]-1];
	if(x==y)return x;
	for(int k=lg[dep[x]]-1; k>=0; k--)
		if(fa[x][k]!=fa[y][k])
			x=fa[x][k],y=fa[y][k];
	return fa[x][0];
}
void solve(int u,int fat) {
	for(int i=head[u]; i; i=edge[i].nxt) {
		int v=edge[i].to;
		if(v==fat)continue;
		solve(v,u);
		chafen[u]+=chafen[v];
	}
}
int main() { //每个节点走了几遍
	scanf("%d",&n);
	for(int i=1; i<=n; i++)scanf("%d",&a[i]);
	for(int i=1; i<n; i++) {
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);
		add(y,x);
	}
	init();
	dfs(1,0);
	for(int i=1; i<=n-1; i++) {
		int u=a[i],v=a[i+1];
		int t=LCA(u,v);
//		cout<<t<<"\n";
		chafen[fa[t][0]]--;
		chafen[t]--;
		chafen[u]++;
		chafen[v]++;
	}
	solve(1,0);
	for(int i=2; i<=n; i++)chafen[a[i]]--;
	for(int i=1; i<=n; i++)cout<<chafen[i]<<"\n";
	return 0;
}
posted @ 2023-01-24 22:43  PKU_IMCOMING  阅读(15)  评论(0)    收藏  举报