倍增求LCA(最近公共祖先)

【模板】

【问题描述】

  给定一棵有n个节点的树,m此询问,每次询问点x和点y的最近公共祖先。

【输入格式】

  第一行一个n,表示这棵树有n个结点。接下来n-1行,每行两个数下x,y,表示下x,y之间有一条边。

然后一个整数m,表示有m个询问,接下来m行,每行两个整数x,y,表示询问点x和点y的最近公共祖先。

【输出格式】

  输出m行,表示询问的结果。

【输入样例】

  6

  1 2

  1 3

  2 4

  2 5

  3 6

  2

  4 5

  2 6

【输出样例】

  2

  1

数据范围

  1<=n<=100000;

  1<=m<=200;

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<ctime>
using namespace std;
const int maxn = 100000 + 10 ;
const int maxk = 20 + 1 ;
struct Node
{int to,next;}edge[maxn*2];
int head[maxn * 2],cnt;
void add(int x,int y)
{
    edge[++cnt].to=y;
    edge[cnt].next=head[x];
    head[x]=cnt;
}
int n,m,Dep[maxn],f[maxn][maxk];//f[x][k]表示x的2^k辈祖先; 
void Deal_first(int pos,int fa)
{
    Dep[pos]=Dep[fa]+1;
    for(int i=0;i<=19;i++)
        f[pos][i+1]=f[f[pos][i]][i];
    for(int i=head[pos];i;i=edge[i].next)
    {
        int son = edge[i].to;
        if(son==fa) continue;
        f[son][0]=pos;
        Deal_first(son,pos);
    }
}
int LCA(int x,int y)
{
    if(Dep[x]<Dep[y]) swap(x,y);
    for(int i=20;i>=0;i--)
    {
        if(Dep[f[x][i]]>=Dep[y]) x=f[x][i];
        if(x==y) return x;
    }
    for(int i=20;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
    return f[x][0];
}
int main()
{
    scanf("%d",&n);
    for(int i=1,a,b;i<n;i++)
    {
        scanf("%d%d",&a,&b);
        add(a,b);add(b,a);
    }
    Deal_first(1,0);
    scanf("%d",&m);
    while(m--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",LCA(a,b));
    }
    return 0;
}

 

posted @ 2019-05-11 09:43  寒方  阅读(143)  评论(0编辑  收藏  举报