头像

欢迎来到我的博客

分享题解与总结

P10113 大量的工作沟通

P10113 大量的工作沟通 - 洛谷

题意

求出m个节点的最近公共祖先,输出 $ 根 → 最近公共祖先$ 路径上的最大编号

屏幕截图 2026-08-15 115423

思路

  1. 多叉树的lca

  2. 0号-根

    \(i\)的父亲是\(f_i\),建立一条\(f_i->i\)\(i->f_i\)的边

  3. 针对每次合作,有m个员工

    找到这m个员工的lca(暴力求可以过)

    \(0-lca\)的链上编号的max

优化

  1. 预处理出\(root-i\)路径上编号的max

图解

屏幕截图 2026-08-15 120821

代码

const int N=1e5+5;
const int K=20;
int n,q,m;
int fa[N][21],depth[N],mx[N];//mx[i]:root-i的最大编号
vector<int> e[N];
vector<int> a;

void dfs1(int x,int f,int lst_mx)
{
    fa[x][0]=f;depth[x]=depth[f]+1;
    for(int i=1;i<=K;++i){
        fa[x][i]=fa[fa[x][i-1]][i-1];
    }

    mx[x]=max(lst_mx,x);
    for(int v:e[x]){
        if(v==f) continue;
        dfs1(v,x,mx[x]);
    }
}

int LCA(int x,int y)
{
    if(depth[x]<depth[y]) swap(x,y);
    for(int i=K;i>=0;--i){
        if(depth[fa[x][i]]>=depth[y]){
            x=fa[x][i];
        }
    }
    if(x==y) return x;
    for(int i=K;i>=0;--i){
        if(fa[x][i]!=fa[y][i]){
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    return fa[x][0];
}

int main()
{
    ios::sync_with_stdio(0),cin.tie(0);
    int fi;
    cin>>n;
    for(int i=1;i<n;++i){
        cin>>fi;
        e[i].push_back(fi);
        e[fi].push_back(i);
    }
    dfs1(0,0,0);
    cin>>q;
    while(q--){
        cin>>m;
        a.clear();a.resize(m);
        for(int i=0;i<m;++i){
            cin>>a[i];
        }
        //求出a[0]-a[m-1]的lca
        int tmp=LCA(a[0],a[1]);
        for(int i=2;i<m;++i){
            tmp=LCA(tmp,a[i]);
        }
        //求出root-lca(a[0]-a[m-1])编号max
        cout<<mx[tmp]<<"\n";
    }
    return 0;
}
posted @ 2026-08-15 12:11  king_steph1209  阅读(12)  评论(0)    收藏  举报