1. 程式人生 > >6031 Innumerable Ancestors (lca)

6031 Innumerable Ancestors (lca)

題目連結

題意:給你一顆含有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;
}