[JLOI2014]松鼠的新家

题目描述

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

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

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

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

输入输出格式

输入格式:

第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an

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

输出格式:

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

输入输出样例

输入样例#1:

5

1 4 5 3 2

1 2

2 4

2 3

4 5

输出样例#1:

1

2

1

2

1

说明

2<= n <=300000

Solution

树上差分中算比较裸的题了...

这道题是点差分(先要记住一个套路,点差分是在lca和其父节点-1,边差分将其转化到点上,在lca上-2)

for (int i=1;i<n;i++) {
int lca=LCA(a[i],a[i+1]);
cnt[a[i]]++, cnt[a[i+1]]++;
cnt[lca]--, cnt[f[0][lca]]--;
}

然后dfs统计就可以了

但是如果仅仅这样的话,我们发现,从a[2]~a[n-1]我们都多统计了一次,所以要减回来,然后因为到了a[n]就停了,所以不要给a[n]准备,也要减

for (int i=2;i<=n;i++) cnt[a[i]]--;

就这样...没了

Code

#include<bits/stdc++.h>
#define in(i) (i=read())
using namespace std; const int N=3e5+10; int read() {
int ans=0,f=1; char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+(i^48),i=getchar();
return ans*f;
} int n,m,cur;
int head[N],nex[N<<1],to[N<<1];
int dep[N],f[25][N],cnt[N],lg[N]={-1},a[N]; void add(int a,int b) {
to[++cur]=b,nex[cur]=head[a],head[a]=cur;
to[++cur]=a,nex[cur]=head[b],head[b]=cur;
} void init() {
for (int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for (int i=1;i<=lg[n];i++)
for (int j=1;j<=n;j++)
f[i][j]=f[i-1][f[i-1][j]];
} void dfs(int u) {
for (int i=head[u];i;i=nex[i]) {
if(to[i]==f[0][u]) continue;
f[0][to[i]]=u, dep[to[i]]=dep[u]+1;
dfs(to[i]);
}
} int LCA(int a,int b) {
if(dep[a] > dep[b]) swap(a,b);
int s=dep[b]-dep[a];
for (int i=lg[s];i>=0;i--)
if(s>>i&1) b=f[i][b];
if(a==b) return a;
for (int i=lg[n];i>=0;i--) {
if(f[i][a]==f[i][b]) continue;
a=f[i][a], b=f[i][b];
}return f[0][a];
} void find(int u) {
for (int i=head[u];i;i=nex[i]) {
if(to[i]==f[0][u]) continue;
find(to[i]); cnt[u]+=cnt[to[i]];
}
} int main()
{
in(n); for (int i=1;i<=n;i++) in(a[i]);
for (int i=1,x,y;i<n;i++)
in(x), in(y), add(x,y);
dfs(1), init();
for (int i=1;i<n;i++) {
int lca=LCA(a[i],a[i+1]);
cnt[a[i]]++, cnt[a[i+1]]++;
cnt[lca]--, cnt[f[0][lca]]--;
}
find(1);
for (int i=2;i<=n;i++) cnt[a[i]]--;
for (int i=1;i<=n;i++) printf("%d\n",cnt[i]);
}
05-11 22:43