题意:
一棵 n n n个节点的树,然后告诉 n n n个地点分别为 x [ i ] x[i] x[i],现在你要从 x [ 1 ] x[1] x[1]走到 x [ 2 ] x[2] x[2]再走到 x [ 3 ] x[3] x[3]…最后走到 x [ n ] x[n] x[n]。然后问你 1 − n 1-n 1−n这些点分别被走过了几次,最后的那一次走到最后一个地点不算次数。 ( n ≤ 300000 ) (n\le300000) (n≤300000)
分析:
设路径为
u
→
v
u\rightarrow v
u→v,差分数组
c
[
i
]
c[i]
c[i],
u
,
v
u,v
u,v两点的公共祖先为
L
C
A
LCA
LCA,
p
r
e
[
]
[
]
pre[][]
pre[][]是父亲数组。
则每走一条路径让
c
[
u
]
+
+
,
c
[
v
]
+
+
,
c
[
L
C
A
]
−
=
1
,
c
[
p
r
e
[
L
C
A
]
[
0
]
]
−
=
1
c[u]++,c[v]++,c[LCA]-=1,c[pre[LCA][0]]-=1
c[u]++,c[v]++,c[LCA]−=1,c[pre[LCA][0]]−=1。
假设前三个地点
1
,
2
,
3
1,2,3
1,2,3
那么从
1
→
2
1\rightarrow 2
1→2这条路径上,
c
[
1
]
+
+
,
c
[
2
]
+
+
,
c
[
L
C
A
]
−
=
1
,
c
[
p
r
e
[
L
C
A
]
[
0
]
]
−
=
1
c[1]++,c[2]++,c[LCA]-=1,c[pre[LCA][0]]-=1
c[1]++,c[2]++,c[LCA]−=1,c[pre[LCA][0]]−=1
2
→
3
2\rightarrow 3
2→3这条路径上,
c
[
2
]
+
+
,
c
[
3
]
+
+
,
c
[
L
C
A
]
−
=
1
,
c
[
p
r
e
[
L
C
A
]
[
0
]
]
−
=
1
c[2]++,c[3]++,c[LCA]-=1,c[pre[LCA][0]]-=1
c[2]++,c[3]++,c[LCA]−=1,c[pre[LCA][0]]−=1
我们发现除第一个地点以外的点都被多计算了一次,最后减掉即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> pii;
const int maxn = 300000 + 5;
const int maxm = 100 + 5;
const int inf = 0x3f3f3f3f;
const LL mod = 1e9 + 7;//19260817
const double pi = acos(-1.0);
int n, cnt, LCA, head[maxn], x[maxn];
LL c[maxn];
int deep[maxn], pre[maxn][22];
struct node{
int to, next;
}edge[maxn << 1];
void addedge(int u, int v){
edge[++cnt].to = v;
edge[cnt].next = head[u];
head[u] = cnt;
}
void dfs1(int x, int f){
pre[x][0] = f;
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(v == f) continue;
deep[v] = deep[x] + 1;
dfs1(v, x);
}
}
void init(){
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= n; i++)
pre[i][j] = pre[pre[i][j - 1]][j - 1];
}
int lca(int u, int v){
if(deep[u] < deep[v]) swap(u, v);
int dc = deep[u] - deep[v];
for(int i = 0; i <= 20; i++){
if((1 << i) & dc) u = pre[u][i];
}
if(u == v) return u;
for(int i = 20; ~i; i--){
if(pre[u][i] != pre[v][i]){
u = pre[u][i];
v = pre[v][i];
}
}
return pre[u][0];
}
void dfs2(int x, int f){
for(int i = head[x]; i; i = edge[i].next){
int v = edge[i].to;
if(v == f) continue;
dfs2(v, x);
c[x] += c[v];
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &x[i]);
for(int i = 1, u, v; i <= n - 1; i++){
scanf("%d %d", &u, &v);
addedge(u, v), addedge(v, u);
}
dfs1(1, 0);
init();
for(int i = 2; i <= n; i++){
LCA = lca(x[i - 1], x[i]);
c[x[i - 1]]++, c[x[i]]++, c[LCA]--, c[pre[LCA][0]]--;
}
dfs2(1, 0);
for(int i = 2; i <= n; i++) c[x[i]]--;
for(int i = 1; i <= n; i++) printf("%lld\n", c[i]);
return 0;
}