6031 Innumerable Ancestors (lca)
阿新 • • 發佈:2018-12-13
題意:給你一顆含有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; }