##LCA Template

LCA Template

主要思想:倍增

首先预处理一一个数组\(lg[]\)\(lg[x]=2^x+1\)

for(int i=1;i<=n;i++)
        lg[i]=lg[i-1]+(i==(1<<lg[i-1]));

再预处理一个数组\(FA[][]\)\(FA[u][x]\)\(u\)\(2^x\)级的祖先。例如,\(FA[u][0]\)\(u\)的父节点编号。
一个重要的“状态转移”式:
\[ FA[u][i]=FA[FA[u][i-1]][i-1]; \]
“爸爸的爸爸是什么?”
\(dfs\)中转移即可。

\(DEP[u]\)表示u节点的深度,指数的参量小于\(\log_2 DEP[u]\)就够了。

void dfs(int u,int fa)
{
    DEP[u]=DEP[fa]+1;
    FA[u][0]=fa;
    for(int i=1;i<lg[DEP[u]];i++)
        FA[u][i]=FA[FA[u][i-1]][i-1];
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v!=fa) dfs(v,u);
    }
}



那么预处理就完成了,接下来要开始跳了;

对于一个询问:\(x\)\(y\),我们想要只要这两个人的最近公共祖先。
“不妨令\(DEP[x] \geq DEP[y]\)”:

if(DEP[x]<DEP[y])swap(x,y);



\(x\)往与\(y\)相同深度的位置跳跃,注意不要超过根节点。这里的原理是\(DEP[x]-2^{lg[DEP[x]-DEP[y]]-1} \geq DEP[y]\)是恒成立的。

while(DEP[x]!=DEP[y])x=FA[x][ lg[DEP[x]-DEP[y]]-1];



好的,现在\(x,y\)都在同一个深度了。如果两人现在是同一个东西,返回;
否则\(x,y\)一起往上跳跃,直到跳到他们\(LCA\)的子节点的位置为止。

for(int k=lg[DEP[x]]-1;k>=0;k--)
{
    if(FA[x][k]!=FA[y][k])
    {
        x=FA[x][k];
        y=FA[y][k];
    }
}



code:

#include <bits/stdc++.h>

using namespace std;

const int N=500005;
int n,m,FA[N][50],s,DEP[N],lg[N];
vector<int>G[N];

inline int read()
{
    char c=getchar();int x=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
        x=x*10+c-'0';
    return x;
}

void dfs(int u,int fa)
{
   // cout<<"DFS"<<endl;
    DEP[u]=DEP[fa]+1;
    FA[u][0]=fa;
    for(int i=1;i<lg[DEP[u]];i++)
    {
        FA[u][i]=FA[FA[u][i-1]][i-1];
    }
    for(int i=0;i<G[u].size();i++)
    {
        int v=G[u][i];
        if(v!=fa)
        {
            dfs(v,u);
        }
    }
    
}

inline int LCA(int x,int y)
{
    if(DEP[x]<DEP[y])swap(x,y);
    while(DEP[x]!=DEP[y])x=FA[x][ lg[DEP[x]-DEP[y]]-1];
    if(x==y)return x;
    for(int k=lg[DEP[x]]-1;k>=0;k--)
    {
        if(FA[x][k]!=FA[y][k])
        {
            x=FA[x][k];
            y=FA[y][k];
        }
    }
    return FA[x][0];
}
int main()
{
   cin>>n>>m>>s;
   
   for(int i=1;i<=n;i++)
        lg[i]=lg[i-1]+(i==(1<<lg[i-1]));
   
   for(int i=1;i<=n-1;i++)
    {
        int u=read();
        int v=read();
        G[u].push_back(v);
        G[v].push_back(u);
    }        
   dfs(s,0);
   

   for(int i=1;i<=m;i++)
   {
        int u=read();
        int v=read();
        printf("%d\n",LCA(u,v));
   }
   return 0;
}





猜你喜欢

转载自www.cnblogs.com/kion/p/11817153.html
lca