题目链接:CodeForce _587C
主要思路:
像倍增处理FA数组一样,倍增处理每个节点到其任一一个祖先的所经过的点集。如Po[i][1]表示从i这个点向上走(2^1)-1步所走过的点集。(由于Po[i][0]表示i这个点的点集,故实际意义中2^i要-1)。最后在加上没有加上的点即可。(听不懂可以看代码)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define M 100005
using namespace std;
struct E {
int nx,to;
} edge[M<<1];
int tot,head[M];
void Addedge(int a,int b) {//正向表存边
edge[++tot].to=b;
edge[tot].nx=head[a];
head[a]=tot;
}
struct path {
int sz;
int num[12];//由于题目只让求前10,故只用开那么大,不然会MLE。
Init(){
sz=0;
}
path() {
sz=0;
}
void operator+=(const int &x){//从定义运算符看着比较舒服
int p=lower_bound(num,num+sz,x)-num;
for(int i=sz;i>=p;i--)num[i]=num[i-1];//插入排序
num[p]=x;
sz=min(sz+1,10);
}
path operator+(const path&_)const {
path res;
int i=0,j=0,k=0;
while(k<10&&i<sz&&j<_.sz) {//归并,注意k不能大于10,每个语句都要加上。
if(num[i]<=_.num[j])res.num[k++]=num[i++];
else res.num[k++]=_.num[j++];
}
while(i<sz&&k<10)res.num[k++]=num[i++];
while(j<_.sz&&k<10)res.num[k++]=_.num[j++];
res.sz=k;
return res;
}
} p[M][20];
int fa[M][20],dep[M],dis[M];
void dfs(int now) {
for(int i=1;(1<<i)<=dep[now];i++){//不能跳过根节点。这条语句也可以改一下放在主函数中dfs完毕后执行
fa[now][i]=fa[fa[now][i-1]][i-1];
p[now][i]=p[now][i-1]+p[fa[now][i-1]][i-1];
}
for(int i=head[now]; i; i=edge[i].nx) {
int nxt=edge[i].to;
if(nxt==fa[now][0])continue;
fa[nxt][0]=now;
dep[nxt]=dep[now]+1;
dfs(nxt);
}
}
path res;
void Up(int &x,int y){
for(int i=0;i<20;i++){
if((1<<i)&y){
res=res+p[x][i];
x=fa[x][i];
}
}
}
void LCA(int a,int b) {
if(dep[a]>dep[b])swap(a,b);
Up(b,dep[b]-dep[a]);
if(a==b){
res=res+p[a][0];
return;
}
for(int i=19;i>=0;i--){
if(fa[a][i]!=fa[b][i]){
res=res+p[a][i]+p[b][i];//res跟着更新
a=fa[a][i];
b=fa[b][i];
}
}
res=res+p[a][1]+p[b][0];//加上剩余没加的三个结点的点集
return ;//相信学过LCA的同学对此都不陌生
}
int val[M];
int main() {
int n,m,q;
scanf("%d%d%d",&n,&m,&q);
for(int i=1; i<n; i++) {
int a,b;
scanf("%d%d",&a,&b);
Addedge(a,b);
Addedge(b,a);
}
for(int i=1; i<=m; i++) {
scanf("%d",&val[i]);
p[val[i]][0]+=i;//初始状态
}
dep[1]=1;
dfs(1);
for(int i=1; i<=q; i++) {
res.Init();
int u,v,a;
scanf("%d%d%d",&u,&v,&a);
LCA(u,v);
int k=min(a,res.sz);
printf("%d ",k);
for(int i=0;i<k;i++)printf("%d ",res.num[i]);
puts("");
}
}