「JLOI2014」松鼠的新家 题解
问题描述
松鼠的新家是一棵树,前几天刚刚装修好了新家,新家有\(n\)个房间,并且有\(n−1\)根树枝连接,每个房间都可以相互到达,且任两个房间之间的路线都是唯一的。天哪,他居然真的住在「树」上。松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去 \(a1\),再去 \(a2\),……,最后到 \(an\),来参观新家。
可是这样会导致**重复走很多房间,懒惰的**不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。**是个馋家伙,立马就答应了。
现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间 \(an\) 是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。
输入格式:
第一行,一个整数 \(n\),表示房间个数。
第二行,\(n\) 个整数,依次描述 \(a1∼an\)
接下来 \(n−1\) 行,每行两个整数 x,y,表示标号 \(x\) 和 \(y\)
的两个房间之间有树枝相连
输出格式:
一共 n
行,第 i 行输出标号为 i
的房间至少需要放多少个糖果,才能让**有糖果吃。
样例输入
5
1 4 5 3 2
1 2
2 4
2 3
4 5
样例输出
1
2
1
2
1
数据范围
对于所有数据,2≤n≤300000
s i l u
就是版子题改了一点点
将每个a[i]与a[i+1]之间都修改一遍
就一模一样!!!
#include <bits/stdc++.h>
using namespace std;
const int N=300002;
int to[N<<2],nxt[N<<2],fir[N<<2];
int diff[N],dist[N],fa[N][30],a[N<<2];
int n,m,ans,cnt,t,x,y;
void add(int x,int y){
to[++cnt]=y;
nxt[cnt]=fir[x];
fir[x]=cnt;
}//链式前向星
void prework(int u,int k){
dist[u]=dist[k]+1,fa[u][0]=k;
for (int i=0;fa[u][i];i++) {
fa[u][i+1]=fa[fa[u][i]][i];
}
for (int i=fir[u];i;i=nxt[i]){
int v=to[i];
if (v!=k) prework(v,u);
}
}//接下来是初始化
int LCA(int u,int v){
if (dist[u]>dist[v]) swap(u,v);
for (int i=t;i>=0;i--) {
if (dist[u]<=dist[v]-(1<<i)) {
v=fa[v][i];
}
}
if (u==v) return u;
for (int i=t;i>=0;i--) {
if (fa[u][i]!=fa[v][i]) {
u=fa[u][i];
v=fa[v][i];
}//同时往上跳
}
return fa[u][0];
}//倍增求LCA
void dfs(int u,int k){
for (int i=fir[u];i;i=nxt[i]){
int v=to[i];
if (v==k) continue;
dfs(v,u);
diff[u]+=diff[v];
}
}//累计
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
t=log(n)/log(2);
for (int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
prework(1,0);
for (int i=1; i<=n-1; i++){
x=a[i],y=a[i+1];
int lca=LCA(x,y);
diff[x]++,diff[y]++;
diff[lca]--;
diff[fa[lca][0]]--; //树上差分
}
dfs(1,0);
for(int i=2;i<=n;i++){
diff[a[i]]--;
}
for(int i=1;i<=n;i++){
printf("%d\n",diff[i]);
}
return 0;
}
完结撒花❀
★,°:.☆( ̄▽ ̄)/$:.°★ 。