P3258 [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
【思路】
倍增/树链剖分 + 树上差分
很有意思很有意思的一道题目
会了树上差分几乎就是一个板子题
不,是两个板子题
倍增/树链剖分板子 + 树上差分板子
先dfs出这棵树每个点的深度和他跳2^n之后会跳到哪一个点
然后按照题目给出的到达房间的顺序
找 \(a_1\)和 \(a_2\)的LCA, \(a_2\) 和 \(a_3\) 的LCA……
然后运用树上差分
将 \(a_i\) 和 \(a_i+1\) 的差分数组都加上1,
然后将LCA和LCA夫妻的差分数组都减去1
最后一个递归递归出每个店的值
输出就好了
注意:
这里有n-1个点作为了起点也作为了终点
所以重复了1次
判断一下重复过的在输出的时候顺手减去1就好了
【完整代码】
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int Max = 300005; struct node { int y; int ne; }s[Max << 1]; int a[Max]; int depth[Max]; int fa[Max][23]; int head[Max]; int sum = 0; int c[Max]; int ans[Max]; void add(int x,int y) { s[++ sum].y = y; s[sum].ne = head[x]; head[x] = sum; s[++ sum].y = x; s[sum].ne = head[y]; head[y] = sum; } void dfs(int f,int fath) { depth[f] = depth[fath] + 1; fa[f][0] = fath; for(register int i = 1;(1 << i) <= depth[f];++ i) fa[f][i] = fa[fa[f][i - 1]][i - 1]; for(int i = head[f];i != 0;i = s[i].ne) if(s[i].y != fath) dfs(s[i].y,f); } int lca(int x,int y) { if(depth[x] < depth[y])swap(x,y); for(register int i = 22;i >= 0;i --) if(depth[fa[x][i]] >= depth[y]) x = fa[x][i]; if(x == y)return x; for(register int i = 22;i >= 0;i --) if(fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i]; return fa[x][0]; } /* void doit(int x) { ans[x] = c[x]; while(fa[x][0] != 0) { ans[fa[x][0]] += ans[x] + a[fa[x][0]]; x = fa[x][0]; } } void search(int x) { int js = 0; for(register int i = head[x];i != 0;i = s[i].ne) { int qwq = s[i].y; if(qwq != fa[x][0]) { js ++; ans[qwq] = ans[x] + c[qwq]; search(qwq); } } if(js == 0) doit(x); } */ int search(int x) { ans[x] = c[x]; for(register int i = head[x];i != 0;i = s[i].ne) { int qwq = s[i].y; if(qwq != fa[x][0]) ans[x] += search(qwq); } return ans[x]; } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); int n; cin >> n; int x,y; for(register int i = 1;i <= n;++ i) cin >> a[i]; for(register int i = 1;i < n;++ i) cin >> x >> y,add(x,y); dfs(1,0); //fa[1][0] = 1; for(register int i = 1;i < n;++ i) { int LCA = lca(a[i],a[i + 1]); c[LCA] -= 1;c[fa[LCA][0]] -= 1; c[a[i]] ++;c[a[i + 1]] ++; } /* for(int i = 1;i <= n;++ i) cout << c[i] << endl; */ int acioi = search(1); for(register int i = 1;i <= n;++ i) { if(i == a[1]) cout << ans[i] << endl; else cout << ans[i] - 1<< endl; } return 0;