LCA-tarjan understand 2
下面是一个最基础的LCA题目 http://poj.org/problem?id=1330
赤裸裸的 题意 输入cas 后 有cas组数据 输入 n 再输入n-1 条边 之后输入x y 问x y的最近公共祖先是什么
#include<stdio.h>
#include<vector>
#include<string.h>
using namespace std;
#define Size 11111 //节点个数 vector<int> node[Size],que[Size];
int n,pare[Size],anse[Size],in[Size],rank[Size]; int vis[Size];
void init()
{
int i;
for(i=;i<=n;i++)
{
node[i].clear();
que[i].clear();
rank[i]=;
pare[i]=i;///
}
memset(vis,,sizeof(vis));
memset(in,,sizeof(in));
memset(anse,,sizeof(anse)); } int find(int nd)//并查集操作 不解释
{
return pare[nd]==nd?nd:pare[nd]=find(pare[nd]);
}
int Union(int nd1,int nd2)//并查集操作 不解释
{
int a=find(nd1);
int b=find(nd2);
if(a==b) return ;
else if(rank[a]<=rank[b])
{
pare[a]=b;
rank[b]+=rank[a];
}
else
{
pare[b]=a;
rank[a]+=rank[b];
}
return ; } void LCA(int root)
{
int i,sz;
anse[root]=root;//首先自成一个集合
sz=node[root].size();
for(i=;i<sz;i++)
{
LCA(node[root][i]);//递归子树
Union(root,node[root][i]);//将子树和root并到一块
anse[find(node[root][i])]=root;//修改子树的祖先也指向root
}
vis[root]=;
sz=que[root].size();
for(i=;i<sz;i++)
{
if(vis[que[root][i]])
{
printf("%d\n",anse[find(que[root][i])]);///root和que[root][i]所表示的值的最近公共祖先
return ;
}
}
return ;
} int main()
{
int cas,i;
scanf("%d",&cas);
while(cas--)
{
int s,e;
scanf("%d",&n);
init();
for(i=;i<n-;i++)
{
scanf("%d %d",&s,&e);
if(s!=e)
{
node[s].push_back(e);
// node[e].push_back(s);
in[e]++;
}
}
scanf("%d %d",&s,&e);
que[s].push_back(e);
que[e].push_back(s);
for(i=;i<=n;i++) if(in[i]==) break;//寻找根节点
// printf("root=%d\n",i);
LCA(i);
}
return ;
}
之后来个加强版
http://acm.hdu.edu.cn/showproblem.php?pid=4547 CD操作 hdu4547
思路:
求出a和b的最近公共祖先,然后分4种情况讨论
①. a和b有一个公共祖先c,则用 c时间戳-a的时间戳+1(1步可以直接从c到b)
②. a是b的祖先,则只用1步就可以到达b点
③. b是a的祖先,则用a的时间戳-b的时间戳
④. a和b是同一个点,则答案是0
参考 http://www.cnblogs.com/Griselda/archive/2013/06/05/3119265.html
#include<stdio.h>
#include<vector>
#include<string.h>
#include<map>
#include<math.h>
#include<string>
using namespace std;
#define Size 111111 //节点个数
struct Query
{
int nd,id;
}temp;
struct out
{
int s,e;
}out[Size];
vector<int> node[Size];
vector<struct Query>que[Size];
int n,m,pare[Size],ance[Size],in[Size],rank[Size],dis[Size],ans[Size],vis[Size];
map<string,int>mp;
void init()
{
int i;
for(i=;i<=n;i++)
{
node[i].clear();
que[i].clear();
rank[i]=;
pare[i]=i;///
}
memset(vis,,sizeof(vis));
memset(in,,sizeof(in));
memset(ance,,sizeof(ance));
memset(dis,,sizeof(dis));
mp.clear();
}
int aabs(int aa)
{
if(aa>) return aa;
else return -aa;
}
int find(int nd)//并查集操作 不解释
{
return pare[nd]==nd?nd:pare[nd]=find(pare[nd]);
}
int Union(int nd1,int nd2)//并查集操作 不解释
{
int a=find(nd1);
int b=find(nd2);
if(a==b) return ;
else if(rank[a]<=rank[b])
{
pare[a]=b;
rank[b]+=rank[a];
}
else
{
pare[b]=a;
rank[a]+=rank[b];
}
return ;
}
void LCA(int root,int num)
{
int i,sz;
ance[root]=root;//首先自成一个集合
dis[root]=num;
sz=node[root].size();
for(i=;i<sz;i++)
{
LCA(node[root][i],num+);//递归子树
Union(root,node[root][i]);//将子树和root并到一块
ance[find(node[root][i])]=root;//修改子树的祖先也指向root
}
vis[root]=;
sz=que[root].size();
for(i=;i<sz;i++)
{
int nd1,nd2,idx,ancestor;
nd1=root;nd2=que[root][i].nd;idx=que[root][i].id;
if(vis[nd2])
{
ans[idx]=ance[find(nd2)];
}
}
return ;
} int main()
{
int cas,i;
scanf("%d",&cas);
while(cas--)
{
char ss[],ee[];
int s,e,cnt=;
scanf("%d %d",&n,&m);
init();
for(i=;i<n-;i++)
{
scanf("%s %s",ee,ss);
if(mp.find(ss)==mp.end())
{
s=cnt;mp[ss]=cnt++;
}
else s=mp[ss];
if(mp.find(ee)==mp.end())
{
e=cnt;mp[ee]=cnt++;
}
else e=mp[ee];
if(s!=e)
{
node[s].push_back(e);
in[e]++;
}
}
for(i=;i<m;i++)
{
scanf("%s %s",ss,ee);
s=mp[ss];e=mp[ee];
out[i].s=s;out[i].e=e;
temp.nd=e;temp.id=i;
que[s].push_back(temp);
temp.nd=s;temp.id=i;
que[e].push_back(temp);
}
for(i=;i<=n;i++) if(in[i]==) break;//寻找根节点
LCA(i,);
for(i=;i<m;i++)
{
if(out[i].s==out[i].e)
printf("0\n");
else
if(out[i].s==ans[i])
printf("1\n");
else if(out[i].e==ans[i])
printf("%d\n",dis[out[i].s]-dis[ans[i]]);
else
printf("%d\n",dis[out[i].s]-dis[ans[i]]+);
}
}
return ;
}
hdu 2874
http://acm.hdu.edu.cn/showproblem.PHP?pid=2874
题目大意: 给你一个n个节点m条边的森林,再给定q个查询,每次查询森林里两个点的最近距离。n ,m <= 10000,q <= 100万
本题和标准的LCA模板应用有了不小的区别 却可以让人更加透彻的看清LCA的思路 而且本题没有必要去求出公共祖先
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define Size 11111
struct Edge
{
int y,val;
}temp;
struct Query
{
int y,id;
}mid;
int pare[Size],ance[Size],vis[Size],dis[Size],rank[Size],ans[+],n,m,c,tree[Size];
vector<struct Query>que[Size];
vector<struct Edge>node[Size];
void init()
{
int i;
for(i=;i<=n;i++)
{
vis[i]=;
pare[i]=i;
dis[i]=;
rank[i]=;
que[i].clear();
node[i].clear();
}
memset(ans,-,sizeof(ans));
}
int find(int x)
{
return pare[x]==x?x:pare[x]=find(pare[x]);
}
/*
void Union(int x,int y)
{
x=find(x);
y=find(y);
if(x!=y)
{
if(rank[x]>rank[y])
{
rank[x]+=rank[y];
pare[y]=x;
}
else
{
rank[y]+=rank[x];
pare[x]=y;
}
}
}
*/
void LCA(int root,int d,int k)//k表示是以第k个点作为根的树
{
int i,sz,nd1,nd2;
vis[root]=; //已经遍历过的点 要标记一下 不要
tree[root]=k;dis[root]=d;
// ance[root]=root;
sz=node[root].size();
for(i=;i<sz;i++)
{
nd2=node[root][i].y;
if(!vis[nd2])
{
LCA(nd2,d+node[root][i].val,k);
// Union(node[root][i].y,root);//用带rank的幷查集操作答案不对 不知道why
int w=find(nd2),m=find(root);
if(w!=m)
{
pare[w]=m;//这样才对
}
//ance[find(node[root][i].y)]=root;
}
}
sz=que[root].size();
for(i=;i<sz;i++)
{
nd1=root;
nd2=que[root][i].y;
if(vis[nd2]&&tree[nd1]==tree[nd2])//如果 nd1 nd2 的跟是同一个点 则是同一棵树上的
{
ans[que[root][i].id]=dis[nd1]+dis[nd2]-*dis[find(nd2)];
}
}
}
int main()
{
int i,j,x,y,val;
while(scanf("%d %d %d",&n,&m,&c)!=EOF)
{
init();
for(i=;i<m;i++)
{
scanf("%d %d %d",&x,&y,&val);
if(x!=y)
{
temp.y=y;temp.val=val;
node[x].push_back(temp);
temp.y=x;
node[y].push_back(temp);//路是2个方向都可以通行的
}
}
for(i=;i<c;i++)
{
scanf("%d %d",&x,&y);
mid.id=i;
mid.y=y;
que[x].push_back(mid);
mid.y=x;
que[y].push_back(mid);
}
for(i=;i<=n;i++)
{
LCA(i,,i);//以每一个节点作为根节点去深度搜索 找出每个点作为根的所有最近公共祖先
}
for(i=;i<c;i++)
{
if(ans[i]==-)
printf("Not connected\n");
else
printf("%d\n",ans[i]);
}
}
return ;
}
/*本题给的是一个森林 而不是一颗树,由于在加入边的时候,我们让2个方向都能走 这样就
形成了一个强连通的快, 对于这个快来说,不管从快上那点出发 都可以遍历这个快上的所
有的点,且相对距离是一样的*/
LCA-tarjan understand 2的更多相关文章
- HDU 2874 Connections between cities(LCA Tarjan)
Connections between cities [题目链接]Connections between cities [题目类型]LCA Tarjan &题意: 输入一个森林,总节点不超过N ...
- POJ 1986 Distance Queries(LCA Tarjan法)
Distance Queries [题目链接]Distance Queries [题目类型]LCA Tarjan法 &题意: 输入n和m,表示n个点m条边,下面m行是边的信息,两端点和权,后面 ...
- LCA Tarjan方法
LCA Tarjan方法 不得不说,高中生好厉害,OI大佬,感觉上个大学好憋屈啊! 说多了都是眼泪 链接拿去:http://www.cnblogs.com/JVxie/p/4854719.html
- LCA tarjan+并查集POJ1470
LCA tarjan+并查集POJ1470 https://www.cnblogs.com/JVxie/p/4854719.html 不错的一篇博客啊,让我觉得LCA这么高大上的算法不是很难啊,嘻嘻嘻 ...
- hihoCoder #1067 : 最近公共祖先·二 [ 离线LCA tarjan ]
传送门: #1067 : 最近公共祖先·二 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 上上回说到,小Hi和小Ho用非常拙劣——或者说粗糙的手段山寨出了一个神奇的网站 ...
- LA 5061 LCA tarjan 算法
题目大意: 给定所有点的权值都为0,给定一棵树以后,每次询问都要求给定两点 x , y 和一个权值w,要求x,y路径上所有点权值加上w,最后求出每一个节点的值 这里因为查询和点都特别多,所以希望能最后 ...
- [CF 191C]Fools and Roads[LCA Tarjan算法][LCA 与 RMQ问题的转化][LCA ST算法]
参考: 1. 郭华阳 - 算法合集之<RMQ与LCA问题>. 讲得很清楚! 2. http://www.cnblogs.com/lazycal/archive/2012/08/11/263 ...
- 最近公共祖先LCA(Tarjan算法)的思考和算法实现
LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现 小广告:METO CODE 安溪一中信息学在线评测系统(OJ) //由于这是第一篇博客..有点瑕疵...比如我把false写成了f ...
- POJ 1330 Nearest Common Ancestors(LCA Tarjan算法)
题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从 ...
- Network POJ - 3694 (LCA+tarjan+桥)
题目链接:https://vjudge.net/problem/POJ-3694 具体思路:首先可以通过缩点的方式将整个图变成一个树,并且树的每条边是桥,但是我们可以利用dfn数组将整个图变成树,这样 ...
随机推荐
- 03 vue项目结构
上一篇已介绍根据vue-cli创建项目,本篇介绍根据vue-cli官方脚手架创建的项目的项目结构. 一.图看结构 build [webpack配置] webpack相关配置,都已经配 ...
- etcd 使用: golang 例子
一:连接到 etcd package main import ( "fmt" "go.etcd.io/etcd/clientv3" "time&quo ...
- 面试题 :10亿url去重只给4G内存
我能想到的有以下几种: 用语言判断去重,ex表格去重,数据库去重,文件名字去重, 有人说:10亿url ex表放不下!! 可以用树和折半的思想将10亿url,变成单元最小化的树,然后用ex表去重 ex ...
- MODFLOW几个版本的区别
GWF = GroundWater Flow MODFLOW-2005 — the GWF Model contains revisions of the commonly used flow pac ...
- (5.11)mysql高可用系列——复制中常见的SQL与IO线程故障
关键词:mysql复制故障处理 [1]手工处理的gtid_next(SQL线程报错) 例如:主键冲突,表.数据库不存在,row模式下的数据不存在等. [1.1]模拟故障:GTID模式下的重复创建用户 ...
- 查找担保圈-step3-获取担保圈路径
USE [test] GO /****** Object: StoredProcedure [dbo].[p01_get_group_path] Script Date: 2019/7/8 14:40 ...
- HYSBZ 1797 Mincut 最小割
Descrption A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站, ...
- # Pycharm打造高效Python IDE
Pycharm打造高效Python IDE 建议以scientific mode运行,在科学计算时,可以方便追踪变量变化,并且会提示函数的用法,比普通模式下的提示更加智能,一般在文件中引入了numpy ...
- 继续:Ruby on Rails 简单了解
一. 接着上一篇继续 1.限制微博的长度 在 Rails 中实现这种限制很简单,使用验证(validation)功能即可.要限制微博的长度最多为 140 个字符 (1).打开文件:app/models ...
- python基础之函数当中的装饰器
在实际工作当中存在一个开放封闭原则 1.对扩展是开放的 为什么要对扩展开放呢? 我们说,任何一个程序,不可能在设计之初就已经想好了所有的功能并且未来不做任何更新和修改.所以我们必须允许代码扩展.添加新 ...