`
kmplayer
  • 浏览: 497276 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

最近公共祖先LCA:Tarjan算法

阅读更多

1,并查集+dfs
对整个树进行深度优先遍历,并在遍历的过程中不断地把一些目前可能查询到的并且结果相同的节点用并查集合并.

2,分类,使每个结点都落到某个类中,到时候只要执行集合查询,就可以知道结点的LCA了。
对于一个结点u.类别有:
以u为根的子树、除类一以外的以f(u)为根的子树、除前两类以外的以f(f(u))为根的子树、除前三类以外的以f(f(f(u)))为根的子树……

类一的LCA为u,类二为f(u),类三为f(f(u)),类四为f(f(f(u)))。这样的分类看起来好像并不困难。
但关键是查询是二维的,并没有一个确定的u。接下来就是这个算法的巧妙之处了。
利用递归的LCA过程。
当lca(u)执行完毕后,以u为根的子树已经全部并为了一个集合。而一个lca的内部实际上做了的事就是对其子结点,依此调用lca.
当v1(第一个子结点)被lca,正在处理v2的时候,以v1为根的子树+u同在一个集合里,f(u)+编号比u小的u的兄弟的子树 同在一个集合里,f(f(u)) + 编号比f(u)小的 f(u)的兄弟 的子树 同在一个集合里…… 
而这些集合,对于v2的LCA都是不同的。因此只要查询x在哪一个集合里,就能知道LCA(v2,x)

还有一种可能,x不在任何集合里。当他是v2的儿子,v3,v4等子树或编号比u大的u的兄弟的子树(等等)时,就会发生这种情况。即还没有被处理。还没有处理过的怎么办?把一个查询(x1,x2)往查询列表里添加两次,一次添加到x1的列表里,一次添加到x2的列表里,如果在做x1的时候发现 x2已经被处理了,那就接受这个询问。(两次中必定只有一次询问被接受).

3,应用:http://acm.pku.edu.cn/JudgeOnline/problem?id=1330
实现代码:
#include<iostream>
#include<vector>
using namespace std;

const int MAX=10001;
int f[MAX];
int r[MAX];
int indegree[MAX];//保存每个节点的入度
int visit[MAX];
vector<int> tree[MAX],Qes[MAX];
int ancestor[MAX];


void init(int n)
{
    for(int i=1;i<=n;i++)
    {

        r[i]=1;
        f[i]=i;
        indegree[i]=0;
        visit[i]=0;
        ancestor[i]=0;
        tree[i].clear();
        Qes[i].clear();
    }

}

int find(int n)
{
    if(f[n]==n)
        return n;
    else
        f[n]=find(f[n]);
    return f[n];
}//查找函数,并压缩路径

int Union(int x,int y)
{
    int a=find(x);
    int b=find(y);
    if(a==b)
        return 0;
    //相等的话,x向y合并
    else if(r[a]<=r[b])
    {
        f[a]=b;
        r[b]+=r[a];
    }
    else
    {
        f[b]=a;
        r[a]+=r[b];
    }
    return 1;

}//合并函数,如果属于同一分支则返回0,成功合并返回1


void LCA(int u)
{
    ancestor[u]=u;
    int size = tree[u].size();
    for(int i=0;i<size;i++)
    {
        LCA(tree[u][i]);
        Union(u,tree[u][i]);
        ancestor[find(u)]=u;
    }
    visit[u]=1;
    size = Qes[u].size();
    for(int i=0;i<size;i++)
    {
        //如果已经访问了问题节点,就可以返回结果了.
        if(visit[Qes[u][i]]==1)
        {
            cout<<ancestor[find(Qes[u][i])]<<endl;
            return;
        }
    }
}


int main()
{
    int cnt;
    int n;
    cin>>cnt;
    while(cnt--)
    {
        cin>>n;;
        init(n);
        int s,t;
        for(int i=1;i<n;i++)
        {
            cin>>s>>t;
            tree[s].push_back(t);
            indegree[t]++;
        }
        //这里可以输入多组询问
        cin>>s>>t;
        //相当于询问两次
        Qes[s].push_back(t);
        Qes[t].push_back(s);
        for(int i=1;i<=n;i++)
        {
            //寻找根节点
            if(indegree[i]==0)
            {
                LCA(i);
                break;
            }
        }
    }
    return 0;
}
分享到:
评论

相关推荐

    LCA (最近公共祖先) Tarjan & 倍增

    LCA Tarjan: 实现原理 理解:离线算法,建好树后再查询,一次DFS 吧所有查询解决完。 时间复杂度:O(n+q); n个点 q次询问 补一下:链式向前星,并查集 ,Tarjan 代码 #include #include #include #include #...

    Tarjan 的 LCA 算法

    c++写的Tarjan 的 LCA 算法,最近公共祖先算法,可供算法学习参考

    Tarjan算法

    最近公共祖先LCA Tarjan算法

    LCA.zip_lca Tarjan pascal_lca pascal_tarjan lca pascal

    Tarjan算法求最近公共祖先,输入树和询问,按询问顺序回答

    Tarjan算法讲义

    Tarjan 算法是图论中非常实用 / 常用的算法之一,能解决强连通分量,双连通分量,割点和桥,求最近公共祖先(LCA)等问题。 关于 Tarjan 算法,笔者将用一系列文章系统介绍 Tarjan 算法的原理以及其主要解决的问题...

    contest_tarjan_LCA_源码

    tarjan离线算法求最近公共祖先。对于有根树T的两个结点u、v,最近公共祖先LCA(T

    Pro 俩顶点之间的长度

    求树中多个两点间距离,实质求LCA(最近公共祖先),(在之前Reference Book中有过论述,CCW在文中也有论述,希望大家有时间好好研读) 常用的是Tarjan 算法或者 倍增算法 或者DFS+ST算法 这道题结果输出所有问询距离...

    欧拉公式求圆周率的matlab代码-CP-Template:竞争性编程的C++模板

    强连接组件(SCC):Tarjan算法 常用技术 欧拉巡回压缩 重光分解(HLD) 最低共同祖先(LCA) 欧拉巡回方法:O(log n)查询 深度方法:O(log n)查询 稀疏表:O(1)查询但很长 质心分解:求解穿过电流质心的所有...

    ACM竞赛代码整理 v0.6.pdf

    ACM竞赛代码整理 ...LCA 最近公共祖先(TARJAN) 16 最大流17 最小费用最大流18 求割点和桥19 无向图的块20 极大双连通分量21 极大强连通分量22 极大强连通分量缩点23 2-SAT 判定24 第五章计算几何25 三维凸包25

    lyq-algorithms-lib:lyq算法库,涉及到相关数据挖掘,解压缩,模式匹配,图算法等多领域算法

    lyq-algorithms-liblyq算法库,涉及到相关数据...##LCA最近公共祖先的离线算法。LZWlzw系列解压缩算法。QQNewsCrawler腾新闻数据爬取工具。RandomForest随机森林算法。Tarjan有向图强连通分量算法。Trie字典查找树算法

    常用算法代码

    | RMQ 离线算法 O(N*LOGN)+O(1)求解 LCA 19 | LCA 离线算法 O(E)+O(1) 20 | 带权值的并查集 20 | 快速排序 20 | 2 台机器工作调度 20 | 比较高效的大数 20 | 普通的大数运算 21 | 最长公共递增子序列 O(N^2) ...

    ACM巨全模板 .pdf

    16.求两个节点的最近公共祖先 (LCA) 17.限制顶点度数的MST(k度限制生成树) 18.多源最短路(spfa,floyd) 19.最短路 (输出字典序最小) 20.最长路 图论题目简述 字符串: 1.字典树(多个字符串的前缀) 2.KMP(关键字搜索) ...

Global site tag (gtag.js) - Google Analytics