LCA Tarjan实现

来源:互联网 发布:温州国际淘宝城网站 编辑:程序博客网 时间:2024/05/22 17:42

Tarjan LCA

以前认为Tarjan算法只是用来解强连通分量的算法,后来发现LCA也有一个Tarjan算法。
下面借一个树来了解一下算法思路。(树已经横向放置)
询问组:
11 9
10 8
6 7
2 3
这里写图片描述
这个算法最好亲手模拟一遍,然后就会感到茅塞顿开。
先从1节点开始DFS深度优先遍历(左节点优先)。
1->2->4->8->10。
发现10没有子节点,找所有关于10的询问,发现询问组有一个10和8的询问,检查发现vis[8]=0,说明8节点并没有被遍历完所有边或者根本就没有遍历过8节点,这样的话我们就不管它。
然后就把10标记上vis[10]=1,然后利用并查集,把它的(直接)父节点记录下来fa[10]=8。
然后就继续回退到8的下一个子节点,找到11,同理,检查询问组发现有11和9的询问,且vis[9]=0,跳过,vis[11]=1,fa[11]=8,回退至8。
8没有子节点可遍历了,检查询问组发现有关于8的询问10和8,而且vis[10]=1,那么我们就返回值fa[10]=8,10和8的LCA就是8,没有其余的关于8的询问了,vis[8]=1,fa[8]=4,回退至4。
4没有子节点可遍历了,检查询问组发现没有关于4的询问,那么就vis[4]=1,fa[4]=2,回退至2。
继续到5和9,9没有子节点可遍历了,检查询问组发现有关于9的询问8和9,而且vis[8]=1,那么我们就返回值findd(fa[8])=2,9和8的LCA就是2,那么就vis[9]=1,fa[9]=5,回退至5。
回退到5,没有询问,标记,回退。
2没有子节点可遍历了,检查询问组发现有关于2的询问2和3,且vis[3]=0,跳过,vis[2]=1,fa[2]=1,回退至1。
1有子节点可遍历,遍历1->3->6。
6没有子节点可遍历了,检查询问组发现有关于2的询问6和7,且vis[7]=0,跳过,vis[6]=1,fa[6]=3,回退至3。
1有子节点可遍历,遍历3->7。
7没有子节点可遍历了,检查询问组发现有关于7的询问6和7,且vis[6]=1,那么我们就返回值fa[6]=3,6和7的LCA就是3,没有其余的关于7的询问了,vis[7]=1,fa[7]=3,回退至3。
3没有子节点可遍历了,检查询问组发现有关于2的询问2和3,且vis[2]=1,那么我们就返回值fa[2]=1,2和3的LCA就是1,没有其余的关于3的询问了,vis[3]=1,fa[3]=1,回退至1。
1没有子节点可遍历了,检查询问组发现没有关于1的询问,结束算法。

鸣谢:yangbowen2同学的纠正!

代码实现比较简单。
代码:

#include<iostream>#include<cstdio>#include<cstdlib>#define MAXX 500001using namespace std;int temp=0,i,j,m,n,s;int tree_hd[MAXX],tree_y[MAXX*2],tree_nxt[MAXX*2];int ask_hd[MAXX],ask_y[MAXX*2],ask_nxt[MAXX*2];int ask_xx[MAXX],ask_yy[MAXX];int fa[MAXX],deep[MAXX],vis[MAXX];int ans[MAXX*4],ans_b[MAXX];int r(){    int aans=0,f=1;    char ch=getchar();    while(ch<'0'||ch>'9')    {        if(ch=='-')            f=-1;        ch=getchar();    }    while(ch>='0'&&ch<='9')    {        aans*=10;        aans+=ch-'0';        ch=getchar();    }    return aans*f;}void tree_add(int xx,int yy){    tree_y[++temp]=yy;    tree_nxt[temp]=tree_hd[xx];    tree_hd[xx]=temp;}void ask_add(int xx,int yy){    ask_y[++temp]=yy;    ask_nxt[temp]=ask_hd[xx];    ask_hd[xx]=temp;}int findd(int fdx){    if(fa[fdx]==fdx) return fdx;    fa[fdx]=findd(fa[fdx]);    return fa[fdx];}void dfs(int x){    int son;    for(int p=tree_hd[x];p;p=tree_nxt[p])    {        son=tree_y[p];        if(!deep[son])        {            deep[son]=deep[x]+1;            dfs(son);            fa[son]=x;            vis[son]=1;        }    }    for(int qq=ask_hd[x];qq;qq=ask_nxt[qq])    {        if(vis[ask_y[qq]])        {            ans[qq]=findd(ask_y[qq]);        }    }}void write(int x){     if(x<0) putchar('-'),x=-x;     if(x>9) write(x/10);     putchar(x%10+'0');}int main(){    freopen("lca.in","r",stdin);    freopen("lca.out","w",stdout);    n=r(),m=r(),s=r();    int xx,yy;    for(i=1; i<n; i++)    {        xx=r(),yy=r();        tree_add(xx,yy);        tree_add(yy,xx);    }    for(i=1;i<=n;i++)    {        fa[i]=i;    }    for(j=1; j<=m; j++)    {        ask_xx[j]=r(),ask_yy[j]=r();        ask_add(ask_xx[j],ask_yy[j]);        ask_add(ask_yy[j],ask_xx[j]);    }    deep[s]=1;    dfs(s);    for(i=1;i<=m;i++)    {        if(ans[i*2-1])        write(ans[i*2-1]),putchar(10);        else if(ans[i*2])        write(ans[i*2]),putchar(10);        else        m++;    }}

这里写图片描述

原创粉丝点击