D题题解
题意:在一个给出的树上找出包含v数组所有点的一棵子树,输出该子树的点数
思路:找出v数组所有点的公共祖先(记为t)后,在以t为根节点的子树上找出到,
……,
到t的路径并将路径上包含的点标记,最后统计被标记点的个数
算法使用:找公共祖先使用lca,找路径使用dfs
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 400005;//无向图需要双倍空间
int n, k, hd[N], ver[N], nxt[N], idx, d[N], f[N][30], t, mk[N], ans;
void add(int x, int y){
ver[++idx] = y;
nxt[idx] = hd[x];
hd[x] = idx;
}
void bfs(){
d[1] = 1;
queue <int> q;
q.push(1);
while(q.size()){
int x = q.front();
q.pop();
for(int i = hd[x];i;i = nxt[i]){
int y = ver[i];
if(d[y]) continue;
q.push(y);
d[y] = d[x]+1;
f[y][0] = x;
for(int j = 1;j <= 25;j++) f[y][j] = f[f[y][j-1]][j-1];
}
}
}
int query(int x, int y){
if(d[x] < d[y]) swap(x, y);
for(int i = 25;i >= 0;i--) if(d[f[x][i]] >= d[y]) x = f[x][i];
if(x == y) return x;
for(int i = 25;i >= 0;i--) if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
//lca模板↑
void dfs(int s){
for(int i = hd[s];i;i = nxt[i]){
int y = ver[i];
if(d[y] <= d[s]) continue;
dfs(y);
if(mk[y]) mk[s] = 1;
}
return;
}
int main(){
cin >> n >> k;
for(int i = 1;i < n;i++){
int x, y;
cin >> x >> y;
add(x, y), add(y, x);
}
bfs();
for(int i = 1;i <= k;i++){//寻找公共祖先
int x;
cin >> x;
mk[x]++;
if(i != 1) t = query(t, x);
else t = x;
}
dfs(t);
for(int i = 1;i <= n;i++){
if(mk[i]) ans++;
}
cout << ans;
return 0;
}