欧拉序求lca

#include <bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn = 5e5+10;
constexpr int maxl = 21;

int n,m,s,tim;
vector<int> gra[maxn];
int first[maxn],dep[maxn<<1],euler[maxn<<1];
int st[maxn<<1][maxl];

void dfs(int u,int p,int deep)
{
    first[u]=++tim;// 第一次进入这个点
    euler[tim]=u;  // euler序
    st[tim][0]=tim;// 存储最小的下标
    dep[tim]=deep; // 对应下标的深度

    for(const int &v : gra[u])
    {
        if(v==p) continue;
        dfs(v,u,deep+1);
        euler[++tim]=u;// 回到这个节点
        st[tim][0]=tim;
        dep[tim]=deep;
    }
}

void buildst()
{
    for(int j=1;(1<<j)<=tim;++j)
    {
        for(int i=1;i+(1<<j)-1<=tim;++i)
        {
            int x=st[i][j-1];// 两个最小的下标
            int y=st[i+(1<<(j-1))][j-1];

            st[i][j]=dep[x]<dep[y] ? x : y;
        }
    }
}

int query(int u,int v)
{
    int l=first[u];
    int r=first[v];
    if(l>r)
    {
        swap(l,r);
    }
    int k=__lg(r-l+1);// 最大二进制
    int x=st[l][k];
    int y=st[r-(1<<k)+1][k];
    return euler[dep[x]<dep[y] ? x : y];
}

signed main()
{
    #ifndef ONLINE_JUDGE
    freopen("cjdl.in","r",stdin);
    freopen("cjdl.out","w",stdout);
    #endif // ONLINE_JUDGE

    scanf("%lld%lld%lld",&n,&m,&s);
    for(int i=1,u,v ;i<n;++i)
    {
        scanf("%lld%lld",&u,&v);
        gra[u].emplace_back(v);
        gra[v].emplace_back(u);
    }

    dfs(s,0,1);
    buildst();

    for(int i=1,u,v ;i<=m;++i)
    {
        scanf("%lld%lld",&u,&v);
        printf("%lld\n",query(u,v));
    }

    return 0;
}
posted @ 2025-11-28 11:36  玖玮  阅读(4)  评论(0)    收藏  举报