LCA 最近公共祖先问题

uvaUVA - 11354 ???

一个比较好的博客给出了大体思路  点击打开链接

lca问题可以同RMQ问题之间相互转化;


总体而言分为五种解法:


解法一:暴力对待

通过二叉查找树进行操作:

解法二:Tarjan算法


poj1330

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>

using namespace std;
const int maxn=10000+5;
int ans[maxn];
int ran[maxn];
int pro[maxn];
int vis[maxn];
int inter[maxn];
vector<int> que[maxn];
vector<int> tree[maxn];
void init(int n)
{
    for(int i=0;i<=n;i++)
    {
        ran[i]=1;
        pro[i]=i;
        que[i].clear();
        tree[i].clear();
        ans[i]=0;
        vis[i]=0;
        inter[i]=0;
    }

}
int find(int x)
{
    if(pro[x]==x)
        return x;
    else
        return pro[x]=find(pro[x]);
}

void uion(int x,int y)
{
    int xx=find(x);
    int yy=find(y);
    if(xx==yy)
        return;
    else if(ran[xx]<ran[yy])
    {
        pro[xx]=yy;
        ran[yy]+=ran[xx];
    }
    else
    {
        pro[yy]=xx;
        ran[xx]+=ran[yy];
    }
}
void lca(int u)
{
    ans[u]=u;
    for(int i=0;i<tree[u].size();i++)
    {
        lca(tree[u][i]);
        uion(u,tree[u][i]);
        ans[find(u)]=u;
    }
    vis[u]=1;
    for(int i=0;i<que[u].size();i++)
    {
        if(vis[que[u][i]])
          cout<<ans[find(que[u][i])]<<endl;
    }

}
int main()
{
     int T,n;
     cin>>T;
     while(T--)
     {
         cin>>n;
         init(n);
         for(int i=0;i<n-1;i++)
         {
             int x,y;
             cin>>x>>y;
             tree[x].push_back(y);
             //ran[x]++;
             inter[y]++;
         }

         int s,t;
         cin>>s>>t;
         que[s].push_back(t);
         que[t].push_back(s);
         for(int i=1;i<=n;i++)
         {
             if(inter[i]==0)
             {
                 lca(i);
                 break;
             }
         }
     }
    return 0;
}



解法三:转换为RMQ问题

解法四:线段树

其余解法

除此之外,还有倍增法、重链剖分算法和后序遍历也可以解决该问题。其中,倍增思路相当于层序遍历,逐层或几层跳跃查,查询时间复杂度为O(log n),空间复杂度为nlogn,对于每个节点先存储向上1层2层4层的节点,每个点有depth信息。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值