版权声明:本文为蒟蒻原创文章,转载请注明出处哦~ https://blog.csdn.net/a54665sdgf/article/details/82933609
题意:给你一颗含有n个结点的根树(树根为1)和Q个查询,每个查询包含两个结点集合A,B,让你从A和B中各选一个结点,使得两结点的lca的深度最大。
解法:先求出每个结点的dfs序,对每个询问的集合A按照dfs序排序,然后对集合B中的每个元素在集合A中二分找到离该元素最近的结点,更新这两个结点的lca深度即可。
#define FRER() freopen("i.txt","r",stdin)
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int INF=0x3f3f3f3f;
int n,Q;
int head[N],to[N<<1],nxt[N<<1],nEdge;
int fa[N],son[N],dep[N],siz[N],top[N],o[N],nnode;
vector<int> A,B;
void AddEdge(int u,int v)
{
nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
}
void dfs1(int u)
{
siz[u]=1,son[u]=-1,o[u]=nnode++;
for(int e=head[u]; ~e; e=nxt[e])
{
int v=to[e];
if(v==fa[u])
continue;
dep[v]=dep[u]+1;
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(!~son[u]||siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u)
{
for(int e=head[u]; ~e; e=nxt[e])
{
int v=to[e];
if(v==fa[u])
continue;
top[v]=v==son[u]?top[u]:v;
dfs2(v);
}
}
int lca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])v=fa[top[v]];
else u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int main()
{
while(scanf("%d%d",&n,&Q)==2)
{
memset(head,-1,sizeof head);
nEdge=nnode=0;
for(int i=1; i<n; ++i)
{
int u,v;
scanf("%d%d",&u,&v);
AddEdge(u,v);
AddEdge(v,u);
}
dep[1]=0,fa[1]=-1,top[1]=1;
dfs1(1),dfs2(1);
while(Q--)
{
A.clear();
B.clear();
int k;
scanf("%d",&k);
while(k--)
{
int u;
scanf("%d",&u);
A.push_back(u);
}
scanf("%d",&k);
while(k--)
{
int u;
scanf("%d",&u);
B.push_back(u);
}
sort(A.begin(),A.end(),[](int a,int b){return o[a]<o[b];});
int ans=0;
for(int i=0;i<B.size();++i)
{
int j=lower_bound(A.begin(),A.end(),B[i],[](int a,int b){return o[a]<o[b];})-A.begin();
if(j<A.size())ans=max(ans,dep[lca(B[i],A[j])]);
if(j>0)ans=max(ans,dep[lca(B[i],A[j-1])]);
}
printf("%d\n",ans+1);
}
}
return 0;
}