分析:
同LCA相似的思路,维护st[ i ][ j ] 代表从节点i往上(不包含i)走2^j个节点前十个最小值集合,这样一直倍增着往上走秩序logn次集合合并即可。
#include <bits/stdc++.h> #define fst first #define snd second #define ALL(a) a.begin(), a.end() #define clr(a, x) memset(a, x, sizeof a) #define rep(i,x) for(int i=0;i<(int)x;i++) #define rep1(i,x,y) for(int i=x;i<=(int)y;i++) #define LOGN 18 typedef long long ll; using namespace std; const int N = 1e5 + 100; vector<int> G[N] , pre[N]; int posi[N],depth[N],fa[N][LOGN],n; vector<int> st[N][LOGN]; void get(vector<int>& a , vector<int>& b){ for(auto v : a) b.push_back(v); sort(ALL(b)); while(b.size() > 10) b.pop_back(); } void dfs(int u,int f,int dep){ depth[u] = dep; fa[u][0] = f; if(f != -1) get(pre[f], st[u][0]); for(auto v:G[u]) if(v != f) dfs( v , u , dep+1); } void build(){ for(int i=0;i<LOGN-1;i++) for(int j=1;j<=n;j++){ fa[j][i+1] = (fa[j][i]==-1 ? -1 : fa[fa[j][i]][i]); if(fa[j][i+1] != -1) { get(st[j][i] , st[j][i+1]); get(st[fa[j][i]][i], st[j][i+1]); } } } void show(int a,vector<int>& ans){ int lim = min(a , (int)ans.size()); printf("%d",lim); rep(i,lim) printf(" %d",ans[i]); printf("\n"); } int cal(int u,int v ,int a){ if(depth[u] > depth[v]) swap(u , v); int cha = depth[v] - depth[u]; vector<int> ans; get(pre[v] , ans); for(int i=LOGN - 1; i>=0;i--){ if((cha>>i)&1){ get(st[v][i] , ans); v = fa[v][i]; } } if(u == v){ show(a , ans); return u; } get(pre[u] , ans); for(int i=LOGN - 1; i>=0;i--){ if(fa[v][i] != fa[u][i]){ get(st[v][i] ,ans); get(st[u][i] ,ans); v = fa[v][i]; u = fa[u][i]; } } get(st[u][0] , ans); show(a , ans); return fa[u][0]; } int m,q; void read(){ scanf("%d %d %d",&n,&m,&q); rep(i,n-1){ int u, v; scanf("%d %d",&u,&v); G[u].push_back(v); G[v].push_back(u); } rep1(i,1,m) scanf("%d",&posi[i]),pre[posi[i]].push_back(i); dfs(1 , -1 , 0); build(); rep1(i,1,n)if(pre[i].size()){ sort(ALL(pre[i])); while(pre[i].size() > 10) pre[i].pop_back(); } int u , v , a; while(q--){ scanf("%d %d %d",&u,&v,&a); cal(u , v , a); } } int main() { read(); return 0; }