[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]);
}