LCA问题有好几种做法,用到(tarjan)图拉算法的就有3种。具体可以看邝斌的博客。http://www.cnblogs.com/kuangbin/category/415390.html

  几天的学习,我就弄懂了离线的Tarjan算法。在此,先鄙视一下哈工大出版的《图论及应用》,离线的Tarjan算法的模版用不了。害我白忙活。

  poj1330的代码可以直接用来当模版。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int f[N], r[N], anc[N];
bool vis[N];
struct node
{
int to,next;
}edge[N*];
int head[N],tot;
void addedge(int i, int j)
{
edge[tot].to=j;edge[tot].next=head[i];head[i]=tot++;
edge[tot].to=i;edge[tot].next=head[j];head[j]=tot++;
}
struct NODE
{
int to,next,index;//index(查询编号)
}query[N*];
int h[N], res[N*], tt, q;
bool flag[N];
void add_q(int i, int j, int k)
{
query[tt].to=j;query[tt].next=h[i];query[tt].index=k;h[i]=tt++;
query[tt].to=i;query[tt].next=h[j];query[tt].index=k;h[j]=tt++;
}
void init(int n)
{
for(int i=;i<=n;i++)
{
f[i]=-;
r[i]=;
vis[i]=;
anc[i]=;
flag[i]=;
tot=tt=;
}
memset(head,-,sizeof(head));
memset(h,-,sizeof(h));
}
int Find(int x)
{
if(-==f[x]) return x;
return f[x]=Find(f[x]);
}
void Link(int x,int y)
{
int a=Find(x),b=Find(y);
if(a!=b)
{
if(r[a]<=r[b]) {f[a]=b; r[b]+=r[a];}
else {f[b]=a; r[a]+=r[b];}
}
}
void LCA(int u)
{
anc[u]=u;
vis[u]=;
for(int k=head[u];k!=-;k=edge[k].next)
{
int v=edge[k].to;
if(vis[v]) continue;
LCA(v);
Link(u,v);
anc[Find(u)]=u;
}
for(int k=h[u];k!=-;k=query[k].next)
{
int v=query[k].to;
if(vis[v])
{
res[query[k].index]=anc[Find(v)];
}
}
}
int main()
{
//freopen("test.txt","r",stdin);
int T,n,u,v,i;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
init(n);
for(i=;i<n;i++)
{
scanf("%d%d",&u,&v);
flag[v]=;
addedge(u,v);
}
q=;
for(i=;i<q;i++)
{
scanf("%d%d",&u,&v);
add_q(u,v,i);
}
int root;
for(i=;i<=n;i++)
if(!flag[i]) {root=i; break;}
LCA(root);
for(i=;i<q;i++)
printf("%d\n",res[i]);
}
return ;
}

 

 hdu2586的要求有些提高,还要求距离。假如要求u和v两点的距离,可以通过求u和v到根结点的距离,还有他们的LCA到根节点的距离。公式是dis[u] + dis[v] -2*dis[LCA[u,v]]。

//hdu2586  O(n+q)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=;
int f[N], r[N], anc[N];
bool vis[N];
struct node
{
int to,next,w;
}edge[N*];
int head[N],tot;
void addedge(int i, int j,int w)
{
edge[tot].to=j;edge[tot].w=w;edge[tot].next=head[i];head[i]=tot++;
edge[tot].to=i;edge[tot].w=w;edge[tot].next=head[j];head[j]=tot++;
}
struct NODE
{
int to,next,index;//index(查询编号)
}query[N*];
int h[N], res[N*], tt, q, dist[N];
bool flag[N];
void add_q(int i, int j, int k)
{
query[tt].to=j;query[tt].next=h[i];query[tt].index=k;h[i]=tt++;
query[tt].to=i;query[tt].next=h[j];query[tt].index=k;h[j]=tt++;
}
void init(int n)
{
for(int i=;i<=n;i++)
{
f[i]=-;
r[i]=;
vis[i]=;
anc[i]=;
flag[i]=;
tot=tt=;
}
memset(head,-,sizeof(head));
memset(h,-,sizeof(h));
}
int Find(int x)
{
if(-==f[x]) return x;
return f[x]=Find(f[x]);
}
void Link(int x,int y)
{
int a=Find(x),b=Find(y);
if(a!=b)
{
if(r[a]<=r[b]) {f[a]=b; r[b]+=r[a];}
else {f[b]=a; r[a]+=r[b];}
}
}
void LCA(int u)
{
anc[u]=u;
vis[u]=;
for(int k=head[u];k!=-;k=edge[k].next)
{
int v=edge[k].to;
if(vis[v]) continue;
dist[v]=dist[u]+edge[k].w;
LCA(v);
Link(u,v);
anc[Find(u)]=u; }
for(int k=h[u];k!=-;k=query[k].next)
{
int v=query[k].to;
if(vis[v])
res[query[k].index]=anc[Find(v)];
}
}
int a[N],b[N];
int main()
{
//freopen("test.txt","r",stdin);
int T,n,u,v,i,m,w;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
init(n);
for(i=;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
flag[v]=;
addedge(u,v,w);
}
for(i=;i<q;i++)
{
scanf("%d%d",&u,&v);
a[i]=u;b[i]=v;
add_q(u,v,i);
}
int root;
for(i=;i<=n;i++)
if(!flag[i]) {root=i; break;}
dist[root]=;
LCA(root);
for(i=;i<q;i++)
printf("%d\n",dist[a[i]]+dist[b[i]]-*dist[res[i]]);
}
return ;
}

LCA 离线的Tarjan算法 poj1330 hdu2586的更多相关文章

  1. (转载)LCA问题的Tarjan算法

    转载自:Click Here LCA问题(Lowest Common Ancestors,最近公共祖先问题),是指给定一棵有根树T,给出若干个查询LCA(u, v)(通常查询数量较大),每次求树T中两 ...

  2. LCA 离线做法tarjan

    tarjan(int u) { int v; for(int i=h[u];i;i=nex[i])//搜索边的 { v=to[i]; tarjan(v); marge(u,v); vis[v]=; } ...

  3. Tarjan算法离线 求 LCA(最近公共祖先)

    本文是网络资料整理或部分转载或部分原创,参考文章如下: https://www.cnblogs.com/JVxie/p/4854719.html http://blog.csdn.net/ywcpig ...

  4. LCA离线算法Tarjan的模板

    hdu 2586:题意:输入n个点的n-1条边的树,m组询问任意点 a b之间的最短距离 思路:LCA中的Tarjan算法,RMQ还不会.. #include <stdio.h> #inc ...

  5. 【POJ 1330 Nearest Common Ancestors】LCA问题 Tarjan算法

    题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从 ...

  6. POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)

    题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从 ...

  7. 『追捕盗贼 Tarjan算法』

    追捕盗贼(COCI2007) Description 为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统.警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N. 警察经常想在罪犯从 ...

  8. [POJ1330]Nearest Common Ancestors(LCA, 离线tarjan)

    题目链接:http://poj.org/problem?id=1330 题意就是求一组最近公共祖先,昨晚学了离线tarjan,今天来实现一下. 个人感觉tarjan算法是利用了dfs序和节点深度的关系 ...

  9. POJ 1470 Closest Common Ancestors (LCA,离线Tarjan算法)

    Closest Common Ancestors Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 13372   Accept ...

随机推荐

  1. Crossing Rivers UVA - 12230 概率与期望

    题目大意:有个人每天要去公司上班,每次会经过N条河,家和公司的距离为D,默认在陆地的速度为1,给出N条河的信息,包括起始坐标p,宽度L,以及船的速度v.船会往返在河的两岸,人到达河岸时,船的位置是随机 ...

  2. BZOJ4756 [USACO17JAN]Promotion Counting晋升者计数

    Description The cows have once again tried to form a startup company, failing to remember from past ...

  3. [luogu2461 SDOI2008] 递归数列 (矩阵乘法)

    传送门 Description 一个由自然数组成的数列按下式定义: 对于i <= k:ai = bi 对于i > k: ai = c1ai-1 + c2ai-2 + ... + ckai- ...

  4. Python学习笔记之异常处理

    1.概念 Python 使用异常对象来表示异常状态,并在遇到错误时引发异常.异常对象未被捕获时,程序将终止并显示一条错误信息 >>> 1/0 # Traceback (most re ...

  5. spi简介(自我理解)

    因为项目中用到spi总线,网上看了下资料,总感觉云山雾罩的,就向身边的同事问了下,他给我解释了下, 我现在把自己理解的写下来 spi一共四条线,一条选择线,一条数据线,2条数据线.spi是一对多设备, ...

  6. 【2】Django安装

    **万物负阴而抱阳,冲气以为和 ** ——老子<道德经> 我们静下心态,开始我们的Django之旅 本节内容 Django的安装 安装结果验证 了解官方文档 1. 安装Django 我们强 ...

  7. Docker在WIN7上的配置

    为什么使用Docker Toolbox Docker在Windows上使用有两种方式,一是利用VirtualBox建立linux虚拟机,在linux虚拟机中安装docker服务端和客户端,二是利用Wi ...

  8. LightOJ - 1231 - Coin Change (I)

    先上题目: 1231 - Coin Change (I)   PDF (English) Statistics Forum Time Limit: 1 second(s) Memory Limit:  ...

  9. JAVA:将反射技术应用于工厂模式(Factory)和单例模式(Singleton)的简单代码

    反射技术大量用于Java设计模式和框架技术,最常见的设计模式就是工厂模式(Factory)和单例模式(Singleton). 参考URL: http://blog.csdn.net/xiaohai79 ...

  10. linux下最简单的端口转发工具

    linux下简单好用的工具rinetd,实现端口映射/转发/重定向 官网地址http://www.boutell.com/rinetd 软件下载wget http://www.boutell.com/ ...