2019.10.01日常总结

【前言】: 今天是祖国母亲70岁生日,请允许我向祖国母亲说一声:“生日快乐!愿您永远繁荣昌盛、山清水秀!”

洛谷 P 3258 : P3258: P3258:

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

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

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

因为松鼠参观指南上的最后一个房间 a n a_n an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
【思路】: 考虑到 n n n比较大( 1 ≤ n ≤ 3 × 1 0 5 1 \leq n \leq 3 \times 10^5 1n3×105),不能直接暴力,所以我们考虑用树上差分算法。
注意,我们不能对边差分,只能对点差分 ,即对于路径 ( x , y ) (x,y) (x,y)上所有点的经过次数 + 1 +1 +1,则进行以下几步( f f f为差分数组): f [ x ] + + , f [ y ] + + , f [ l c a ( x , y ) ] − − , f [ f a ( l c a ( x , y ) ) ] − − f[x]++,f[y]++,f[lca(x,y)]--,f[fa(lca(x,y))]-- f[x]++,f[y]++,f[lca(x,y)],f[fa(lca(x,y))]
【代码】:

#include 
using namespace std;
const int N=301000;
struct node{
	int next,to;
}e[N<<1];int h[N],tot;
inline void add(int a,int b){
	e[++tot]=(node){h[a],b};h[a]=tot;
	e[++tot]=(node){h[b],a};h[b]=tot;
}//链式前向星
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
	char c=0;int x=0;bool f=0;
	while (!g(c)) f=c=='-',c=gc;
	while (g(c)) x=x*10+c-48,c=gc;
	return f?-x:x;
}//读入优化的模板
int f[N][22],dep[N];
void dfs_init(int u,int fa){
	dep[u]=dep[fa]+1;
	for(int i=0;i<20;i++)
	f[u][i+1]=f[f[u][i]][i];
	for(int i=h[u];i;i=e[i].next){
		register int v=e[i].to;
		if (v==fa) continue;
		f[v][0]=u;dfs_init(v,u);
	}
}
inline int lca(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	for(int i=20;i>=0;i--)
	if (dep[f[x][i]]>=dep[y]){
		x=f[x][i];
	}
	if (x==y) return x;
	for(int i=20;i>=0;i--)
	if (f[x][i]!=f[y][i]){
		x=f[x][i];y=f[y][i];
	}
	return f[x][0];
}
int dp[N];
void get_answer(int u){
	for(int i=h[u];i;i=e[i].next){
		register int v=e[i].to;
		if (v==f[u][0]) continue;
		get_answer(v);dp[u]+=dp[v];
	}
}
int n,x,y,i,a[N];
int main(){
	n=read();
	for(i=1;i<=n;i++)
	a[i]=read();
	for(i=1;i<n;i++)
	add(read(),read());
	dfs_init(1,0);
	for(i=2;i<=n;i++){
		dp[a[i-1]]++;dp[a[i]]++;
		dp[lca(a[i-1],a[i])]--;
		dp[f[lca(a[i-1],a[i])][0]]--;
	}
	get_answer(1);
	for(i=2;i<=n;i++)
	dp[a[i]]--;//注意这里哦
	for(i=1;i<n;i++)
	printf("%d\n",dp[i]);
	printf("%d",dp[n]);
	return 0;
}

你可能感兴趣的:(原创)