lca Tarjan学习笔记

来源:互联网 发布:太极集团知乎 编辑:程序博客网 时间:2024/06/05 21:11

http://blog.csdn.net/hnust_xiehonghao/article/details/9109295

 

首先这是一个离线算法,必须把所有的询问都输入之后,再能O(n)处理他们的LCA

 

Tarjan实现思路:

这个算法是基于并查集和DFS的。

Dfs的作用呢,就是递归,一次对树中的每一个节点进行处理。

而并查集的作用就是当dfs每访问完(注意,这里是访问完)到一个点的时候,就通过并查集将这个点,和它的子节点链接在一起构成一个集合,也就是将并查集中的pnt值都指向当前节点。这样就把树中的节点分成了若干个的集合,然后就是根据这些集合的情况来对输入数据来进行处理。

 

Tarjan实现方法:

Tarjan算法是利用并查集来实现的。它按DFS的顺序遍历整棵树。

对于每个结点x,它进行以下几步操作:


1 在并查集中建立仅有u的集合,设置该集合的祖先为u
1 对u的每个孩子v:
   1.1 tarjan之
   1.2 合并v到父节点u的集合,确保集合的祖先是u
2 设置u为已遍历
3 处理关于u的查询,若查询(u,v)中的v已遍历过,则LCA(u,v)=v所在的集合的祖先

poj1330裸题:

#include<cstdio>#include<cmath>#include<cstdlib>#include<algorithm>#include<cstring>using namespace std;const int N=25005;inline int read(){int ans,f=1;char ch;while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';return ans*f;}int head[N],to[N*2],pre[N*2];int n,tot,ans,fa[N];int x,y;void addedge(int x,int y){to[++tot]=y;pre[tot]=head[x];head[x]=tot;}bool b[N];int find(int x){return x==fa[x] ? x:fa[x]=find(fa[x]);}void work(int u){fa[u]=u;//步骤1for (int i=head[u];i;i=pre[i]){work(to[i]);fa[to[i]]=u;}//步骤2b[u]=true;//步骤3if (u==x&&b[y]) ans=find(y);if (u==y&&b[x]) ans=find(x);//步骤4,处理当前节点有关的询问,这道题因为只有一个询问,所以直接这么搞了。同时注意:要注意两个方向的询问!! }void work(){n=read();memset(head,0,sizeof(head));memset(b,false,sizeof(b));memset(fa,0,sizeof(fa));for (int i=1;i<n;i++){x=read(),y=read();addedge(x,y);b[y]=true;}x=read(),y=read();int rt;for (int i=1;i<=n;i++) if (!b[i]) rt=i;memset(b,false,sizeof(b)); work(rt);printf("%d\n",ans);}int main(){int T=read();while(T--) work();return 0;}


 

 

 

技巧:对于求两个点的距离时,很巧妙的用到了差分的思想,dis【v】+dis【u】-dis【lca(u,v)】*2

0 0
原创粉丝点击