Company Queries II

/*
Company Queries II
https://cses.fi/problemset/task/1688/

这题就是求lca的模板题
下面代码用倍增法

*/
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;
vector<int> g[N];
int fa[N][20], d[N];
int n,q,a,b;

void dfs(int x, int f){
    d[x]=d[f]+1; fa[x][0]=f;
    // cout<<x<<" depth: "<<d[x]<<endl;
    for(auto y: g[x]){
        if(y!=f)
            dfs(y, x);
    }
}
/*
先将 $a$ 和 $b$ 中较低的节点提升到与另一个节点相同的深度。
 然后,我们将这两个节点依次递减地向上提升。最后,任一节点的父节点就是这两个节点的 LCA。
*/
int lca(int x, int y){
    if(d[x]<d[y]) swap(x, y);
    int k=d[x]-d[y];
    for(int i=19;i>=0;i--){
        if((k>>i)&1) x=fa[x][i];
    }
    if(x==y) return y;
    for(int i=19;i>=0;i--){
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i], y=fa[y][i];
    }
    return fa[x][0];
}
int main()
{
    cin>>n>>q;
    for(int i=2;i<=n;i++){
        int t;
        cin>>t;
        g[t].push_back(i);
        g[i].push_back(t);
    } 
    dfs(1, 0);
    for(int k=1;k<20;k++)
        for(int i=1;i<=n;i++)
        {
            int m=fa[i][k-1];
            fa[i][k]=fa[m][k-1];
            // cout<<i<<" "<<k<<" fa:"<<fa[i][k]<<endl;
        }
    
    while(q--){
        cin>>a>>b;
        cout<<lca(a, b)<<'\n';
    }
    return 0;
}

欧拉序做法:

/*
Company Queries II
https://cses.fi/problemset/task/1688/

这题就是求lca的模板题
用欧拉序处理

*/
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+10;

vector<int> g[N];
int fa[N][20], d[N];
int n,q,a,b;

int timer, tin[N], tout[N];//记录进入和出来的时间
void dfs(int x, int f){
    fa[x][0]=f;
    tin[x]=++timer;
    // cout<<"tin "<<x<<": timer "<<tin[x]<<endl;
    // cout<<x<<" depth: "<<d[x]<<endl;
    for(auto y: g[x]){
        if(y!=f)
            dfs(y, x);
    }
    tout[x]=timer;
    // cout<<"tout "<<x<<": timer "<<tout[x]<<endl;
}

//判断 x 是否是 y 的祖先
bool is_ancestor(int x, int y){
    return tin[x]<=tin[y] && tout[x]>=tout[y];
}

/*
1、先判断是否有祖先关系,有的话,直接返回
2、否则,类似倍增, 我们将这其中一个节点依次递减地向上提升
*/
int lca(int x, int y){
    if(is_ancestor(x, y)) return x;
    if(is_ancestor(y, x))  return y;

    for(int i=19;i>=0;i--){
        if(fa[x][i] && !is_ancestor(fa[x][i], y)) //如果不是0号结点,且不是祖先
            x=fa[x][i];//往上跳
    }
    return fa[x][0]; //最后x的父亲必定是x与y的LCA
}
int main()
{
    cin>>n>>q;
    for(int i=2;i<=n;i++){
        int t;
        cin>>t;
        g[t].push_back(i);
        g[i].push_back(t);
    } 
    dfs(1, 0);
    for(int k=1;k<20;k++)
        for(int i=1;i<=n;i++)
        {
            int m=fa[i][k-1];
            fa[i][k]=fa[m][k-1];
            // cout<<i<<" "<<k<<" fa:"<<fa[i][k]<<endl;
        }
    
    while(q--){
        cin>>a>>b;

        cout<<lca(a, b)<<'\n';
    }
    return 0;
}

posted @ 2025-04-29 14:52  katago  阅读(10)  评论(0)    收藏  举报