思路:
只要保证每个点都只被标记一次就行了
于是我们用LCA加一些模拟来做
c o d e code code
#include<iostream>
#include<cstdio>
#define ll long long
#define re register
using namespace std;
const ll MAXN = 5e5 + 10;
ll n, m, s, a[MAXN];
ll head[MAXN], tot, f[MAXN][25], dep[MAXN];
bool v[MAXN];
struct node {
ll to, next;
}b[MAXN * 2];
inline void add(re ll x, re ll y) {
b[++ tot] = (node) { y, head[x] };
head[x] = tot;
}
inline void dfs(re ll x, re ll fa) {
f[x][0] = fa;
dep[x] = dep[fa] + 1;
for(re ll i = head[x]; i; i = b[i].next) {
re ll y = b[i].to;
if(fa == y) continue;
dfs(y, x);
}
}
inline ll lca(re ll x, re ll y) {
if(dep[x] > dep[y]) swap(x, y);
re ll k = dep[y] - dep[x], j = 20;
while(k) {
re ll t = (1 << j);
if(k >= t) k -= t, y = f[y][j];
j --;
}
if(x == y) return x;
for(re ll i = 20; i >= 0; -- i)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
inline void do_(re ll x, re ll y) {
while(v[x] == 0 && x != y) {
v[x] = 1;
x = f[x][0];
}
v[y] = 1;
}
inline void do2_(re ll x, re ll y) {
while(x != y) {
re ll j = 0;
while(v[f[x][j]] == 1) {
++ j;
if(dep[f[x][j - 1]] <= dep[y]) return;
}
if(j == 0) {
x = f[x][0];
break;
}
x = f[x][j - 1];
}
while(v[x] == 0 && x != y) {
v[x] = 1;
x = f[x][0];
}
v[y] = 1;
}
int main() {
scanf("%lld%lld%lld", &n, &m, &s);
v[s] = 1;
for(re ll i = 1; i < n; ++ i) {
re ll x, y;
scanf("%lld%lld", &x, &y);
add(x, y), add(y, x);
}
dfs(1, 0);
for(re ll j = 1; j <= 20; ++ j)
for(re ll i = 1; i <= n; ++ i)
f[i][j] = f[f[i][j - 1]][j - 1];
for(re ll i = 1; i <= m; ++ i) scanf("%lld", &a[i]);
ll i = 1, ans = 0;
while(i <= m) {
if(v[a[i]]) {
i ++;
continue;
}
re ll k = lca(s, a[i]);
do_(a[i], k);
do2_(s, k);
ans += dep[a[i]] + dep[s] - dep[k] * 2;
s = a[i];
}
printf("%lld", ans);
return 0;
}