洛谷 P3258 [JLOI2014]松鼠的新家(LCA+树上差分)
Description:
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。
松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去a1,再去a2,…,最后到an,去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。
维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。
因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。
Input:
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an
接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。
2<= n <=300000
Output:
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。
Sample Input:
5
1 4 5 3 2
1 2
2 4
2 3
4 5
Sample Output:
1
2
1
2
1
题目链接
按照顺序走树上顶点,经过的顶点点权++,求每个顶点的最小点权。
用树上差分对相邻两点路径上经过的所有点进行计数,因为总路径起始两点外所有点会被计算两次(起点+终点),所以最后减去一次,而总路径终点不放糖,所以也需要减去一次。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 5;
struct Edge {
int V, Next;
};
Edge edges[maxn << 1];
int Head[maxn];
int Tot;
void Init() {
Tot = 0;
memset(Head, -1, sizeof(Head));
}
void AddEdge(int U, int V) {
edges[Tot] = Edge {V, Head[U]};
Head[U] = Tot++;
}
int Rmq[maxn << 1];
struct ST {
int Dp[maxn << 1][20];
void Init(int N) {
for (int i = 1; i <= N; ++i) {
Dp[i][0] = i;
}
for (int j = 1; (1 << j) <= N; ++j) {
for (int i = 1; i + (1 << j) - 1 <= N; ++i) {
Dp[i][j] = Rmq[Dp[i][j - 1]] < Rmq[Dp[i + (1 << (j - 1))][j - 1]] ? Dp[i][j - 1] : Dp[i + (1 << (j - 1))][j - 1];
}
}
}
int Query(int Left, int Right) {
if (Left > Right) {
swap(Left, Right);
}
int Len = int(log2(Right - Left + 1));
return Rmq[Dp[Left][Len]] <= Rmq[Dp[Right - (1 << Len) + 1][Len]] ? Dp[Left][Len] : Dp[Right - (1 << Len) + 1][Len];
}
};
int Vertex[maxn << 1];
int First[maxn];
int Parent[maxn];
int LCATot;
ST St;
void LCADfs(int Cur, int Pre, int Depth) {
Vertex[++LCATot] = Cur;
First[Cur] = LCATot;
Rmq[LCATot] = Depth;
Parent[Cur] = Pre;
for (int i = Head[Cur]; ~i; i = edges[i].Next) {
if (edges[i].V == Pre) {
continue;
}
LCADfs(edges[i].V, Cur, Depth + 1);
Vertex[++LCATot] = Cur;
Rmq[LCATot] = Depth;
}
}
void LCAInit(int Root, int NodeNum) {
LCATot = 0;
LCADfs(Root, 0, 0);
St.Init(2 * NodeNum - 1);
}
int QueryLCA(int U, int V) {
return Vertex[St.Query(First[U], First[V])];
}
int N;
int A[maxn];
int Cnt[maxn];
int Dfs(int Cur, int Pre) {
for (int i = Head[Cur]; ~i; i = edges[i].Next) {
if (edges[i].V == Pre) {
continue;
}
Cnt[Cur] += Dfs(edges[i].V, Cur);
}
return Cnt[Cur];
}
int main(int argc, char *argv[]) {
Init();
scanf("%d", &N);
for (int i = 1; i <= N; ++i) {
scanf("%d", &A[i]);
}
for (int i = 1, X, Y; i < N; ++i) {
scanf("%d%d", &X, &Y);
AddEdge(X, Y);
AddEdge(Y, X);
}
Parent[1] = 0;
LCAInit(1, N);
memset(Cnt, 0, sizeof(Cnt));
for (int i = 1; i < N; ++i) {
int LCA = QueryLCA(A[i], A[i + 1]);
Cnt[A[i]]++; Cnt[A[i + 1]]++;
Cnt[LCA]--; Cnt[Parent[LCA]]--;
}
Dfs(1, 0);
for (int i = 2; i <= N; ++i) {
Cnt[A[i]]--;
}
for (int i = 1; i <= N; ++i) {
printf("%d\n", Cnt[i]);
}
return 0;
}