虚树这一个知识点刚开始看都摸不清头脑,集中精力看了一个多小时发现原来挺简单的,可能是理解了的东西都会觉得简单吧。。这边有位大佬写的可以–》》https://www.cnblogs.com/chenhuan001/p/5639482.html不过它的这个lca我觉得没我的清晰。。可能是我太菜了,看不懂他优化了的吧。。
下面是我写的模板:
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
struct edge{ //链式向前星
int to,next;
}edges[N<<1];
int head[N],cnt;
void add_edge(int u,int v){ //连边
edges[++cnt].next = head[u];
edges[cnt].to = v;
head[u] = cnt;
}
//fa:表示每个节点的祖先,dep:表示每个节点的深度,id:表示每个节点的编号
int fa[N][50],dep[N],lg[N],id[N],ind;
int n,m,s; //n:表示节点数以及n-1条边,m:表示查询的节点有m个,s表示根
/**
* lg_init():初始化log2
*/
void lg_init(int n){
for(int i = 1;i<=n;i++){
lg[i] = lg[i-1] + (1 << lg[i-1] == i);
}
}
/**
* dfs():找出每个节点的2^(i-1)的祖先,每个节点的深度,给每个节点编号
*/
void dfs(int x,int fath){
fa[x][0] = fath, dep[x] = dep[fath] + 1,id[x] = ++ind;
for(int i = 1;i<=lg[dep[x]]; i++){
fa[x][i] = fa[fa[x][i-1]][i-1];
}
for(int i = head[x]; i; i = edges[i].next){
int to = edges[i].to;
if(to != fath) dfs(to,x);
}
}
/**
* LCA():求最近公共祖先
*/
int LCA(int x,int y){
if(dep[x] < dep[y]) swap(x,y);
while(dep[x] > dep[y]) x = fa[x][lg[dep[x] - dep[y]] - 1];
if(x == y) return x;
for(int i = lg[dep[x]] - 1; i >= 0; i--){
if(fa[x][i] != fa[y][i]) x = fa[x][i],y = fa[y][i];
}
return fa[x][0];
}
// 虚树邻接表
vector<int> vtree[N];
vector<int> vtreew[N];
int stk[N],top; //存放虚树节点的栈
int mark[N]; //标记
/**
* tree_add():给虚树节点连边
*/
void tree_add(int u,int v,int w){
vtree[u].push_back(v);
vtree[v].push_back(u);
vtreew[u].push_back(w);
vtreew[v].push_back(u);
}
struct Vtree{
int id,order;
}tree[N];
int cmp(Vtree a,Vtree b){
return a.order < a.order;
}
int build_vtree(int vp[],int vn){
if(vn == 0) return -1;
top = 0;
stk[top++] = vp[0];
vtree[vp[0]].clear();
vtreew[vp[0]].clear();
mark[vp[0]] = 1;
for(int i = 1;i<vn;i++){
int v = vp[i];
int lca = LCA(stk[top-1],v);
if(lca == stk[top-1]); //如果v和栈顶结点的公共祖先 == 栈顶元素,那么不用做任何操作
else{
int pos = top-1;
while(pos>=0 && dep[stk[pos]] > dep[lca]) pos--;
pos++;
for(int j = pos; j<top-1;j++){
tree_add(stk[j],stk[j+1],dep[stk[j+1]] - dep[stk[j]]);
}
int prepos = stk[pos];
if(pos == 0){
vtree[lca].clear(),vtreew[lca].clear(),stk[pos] = lca, top = pos+1;
mark[lca] = 0;
}
else if(stk[pos] != lca){
vtree[lca].clear(),vtreew[lca].clear(),stk[pos] = lca,top = pos+1;
mark[lca] = 0;
}else
top = pos;
tree_add(prepos,lca,dep[prepos] - dep[lca]);
}
vtree[v].clear();
vtreew[v].clear();
stk[top++] = v;
mark[v] = 1;
}
for(int i = 0;i<top-1;i++){
tree_add(stk[i],stk[i+1],dep[stk[i+1]] - dep[stk[i]]);
}
return vp[0];
}
int solve(int vp[],int vn){
for(int i = 0;i<vn;i++) tree[i].id = vp[i],tree[i].order = id[vp[i]];
sort(tree,tree+vn,cmp);
for(int i = 0;i<vn;i++) vp[i] = tree[i].id;
return build_vtree(vp,vn);
}
void print(int x,int fath){
printf("%d ",x);
for(int i = 0;i<vtree[x].size();i++){
if(vtree[x][i] != fath) print(vtree[x][i],x);
}
}
int main(){
cin >> n >> m >> s;
int u,v;
for(int i = 0;i<n-1;i++){
cin >> u >> v;
add_edge(u,v);
add_edge(v,u);
}
lg_init(n);
dfs(s,0);
int save[m];
for(int i = 0;i<m;i++) cin >> save[i];
int root = solve(save,m);
if(root != -1){
print(root,fa[root][0]);
}
// cout << LCA(4,5) << endl;
system("pause");
return 0;
}
/*
7 3 1
1 3
1 2
2 6
3 5
3 4
4 7
6 7 5
*/