mltang

博客园 首页 新随笔 联系 订阅 管理

这个算法  我个人认为是  遍历每一个点把它当成一些询问的最近祖先

        1

      2    3

    4     5  6

low是并差集,vis是是否访问过,访问过为true,没有为false;

假设询问是(4,4),(4,5),(2,6),(3,6)

 

按程序最先递归到4点,之后4没有了后继节点,

vis[4] = true;

证明4已经访问过了,然后就开始遍历4的询问,发现4有两个询问,第一个是(4,4),现在4是true,

那么就是说4是到过的点,然后我们就find祖先,因为没有点进行low数组的更新(就是当前节点low值没有指向父节点),意味着父祖先卡死在了4这个点,输出4

然后发现(4,5)也是一个询问,但是明显vis[5] = false;那么就不进行查找

 

回到2点,跟新low[4] = 2,然后发现

2除了4,没有后继节点,

vis[2]  =true;

有一个询问(2,6)但是vis[6] = false;所以不find。

 

然后回到1,跟新  low[2] = 1;

进入右边的3,又进入了右边的5,没有后继节点,

之后看询问,发现有一个询问就是我们没有处理的(4,5),这时候发现vis[4] = true于是find(4) == 1

 

回到3点,跟新low值low[5] = 3;

进入6点

 

进入6发现

6点没有子节点,

vis[6] = true

有一个2,6询问,这时2,6都是true之后find(2) == 1,

有一个(3,6)询问,但是3是false,不询问,返回3点

 

返回3点

low[6] = 3;

3点走完了子节点

vis[3] = true;

有一个(3,6)询问,vis[3] && vis[6]  所以find(6) == 3

3走完了返回1

 

返回1,low[3] = 1

子节点走完了

vis[1] = true;

没有询问

程序结束

 

bb这么多,画一遍图就明白了,我觉得这个东西像一个树的合并,每次返回到上一层都是一次合并,就像(4,5)的询问一样,

我认为这时候是1的左子树和右子树进行了合并,而我们递归是一层层向上返回的,所以找到的第一个点就是合并的那个点

 

这个东西我个感觉为和tarjin算法关系不是很大,但是网上很多求法都说lca用tarjin算法,我估计还是我这个对tarjin算法的理解不够到位,

要是那里说的不对,还是请多指点一下

void lca(int u)

{

    int i,j;

    vis[u] = true;

    for(i = 0;i < pp[u].size(); ++i)

    {

        j = pp[u][i];

        if(vis[j] == true)

            cout << findx(u) << endl;

    }

    for(i = 0; i < p[u].size(); ++i)

    {

        j = p[u][i];

        lca(j);

        low[j] = u;

    }

}

int findx(int x)

{

    if(x == low[x])

        return x;

    return low[x];

}

posted on 2017-11-10 18:04  mltang  阅读(182)  评论(0编辑  收藏  举报