-->

LCA ST表

2020-12-02 06:43发布

//LCA
//ST表 在线 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define maxn 500001
using namespace std;
int n,m,cnt,root,head[maxn],depth[maxn];
int order[2*maxn],first[maxn];//order[x]dfs中第x次遍历的点(重复) first[x]记录点x在dfs中首次遍历顺序(不重复) 
int lg[2*maxn],f[2*maxn][21];//lg[x]记录log2x的向下取整值  f[x][k]表示包含x点共2^k个点中最小值 
struct uio{
    int next,to;
}edge[2*maxn];
void add(int x,int y)
{
    edge[++cnt].next=head[x];
    edge[cnt].to=y;
    head[x]=cnt;
}
void dfs(int x,int pre)//pre为上次遍历过节点 防止走重 
{
    order[++cnt]=x;
    first[x]=cnt;
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        int u=edge[i].to;
        if(u!=pre)
        {
            depth[u]=depth[x]+1;
            dfs(u,x);
            order[++cnt]=x;
        }
    } 
} 
void ST()
{
    for(int i=1;i<=cnt;i++)
        f[i][0]=order[i];
    lg[1]=0,lg[2]=1;
    for(int i=3;i<=cnt;i++)
    {
        lg[i]=lg[i-1];
        if(1<<lg[i-1]+1==i)
            lg[i]++;
    }
    int num=lg[cnt];
    for(int j=1;j<=num;j++)
        for(int i=1;i+(1<<j)-1<=cnt;i++)// i+(1<<j)-1 -1原因:区间包括自身 
        {
            if(depth[f[i][j-1]]<depth[f[i+(1<<j-1)][j-1]])
                f[i][j]=f[i][j-1];
            else
                f[i][j]=f[i+(1<<j-1)][j-1];
        }
}
int    RMQ(int l,int r)
{
    int k=lg[r-l+1];
    if(depth[f[l][k]]<depth[f[r-(1<<k)+1][k]])//r-(1<<k)+1 +1原因:区间包括自身 
        return f[l][k];
    else return f[r-(1<<k)+1][k];//此处+1原因同上 
}
int ask(int x,int y)
{
    x=first[x];
    y=first[y];
    if(x>y)
        swap(x,y);
    return RMQ(x,y);
}
int main()
{
    scanf("%d%d%d",&n,&m,&root);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n-1;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    cnt=0;
    dfs(root,-1);
    ST();
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        printf("%d\n",ask(u,v));
    }
    return 0;
}

 

标签: