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数组将整个图变成树,这样 ...
随机推荐
- python导入csv文件出现SyntaxError问题分析
python导入csv文件出现SyntaxError问题分析 先简单描述下碰到的题目,要求是写出2个print的结果 可以看到,a指向了一个列表list对象,在Python中,这样的赋值语句,其实内部 ...
- UITableViewCell点击不能push解决方法
一般情况下不能push是因为当前控制器没有导航控制器,造成不能push的情况. 解决方法如下: - (void)tableView:(UITableView *)tableView didSelect ...
- 2单表CRUD综合样例开发教程
东软集团股份有限公司 基础软件事业部 单表CRUD综合样例开发教程 东软机密 tui 更改履历 版本号 更改时间 更改的 图表和章节号 状态 更改简要描述 更改申 请编号 更改人 批准人 V1.0 2 ...
- 我想学前端动画-CSS之transition
Transition属性: 属性 描述 CSS transition 简写属性,用于在一个属性中设置四个过渡属性. 3 transition-property 规定应用过渡的 CSS 属性的名称.默认 ...
- 【HANA系列】SAP HANA SQL条件判断是NULL的写法
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL条件判断 ...
- C#编程 线程,任务和同步(1) 基础认识
线程 对于所有需要等待的操作,例如移动文件,数据库和网络访问都需要一定的时间,此时就可以启动一个新的线程,同时完成其他任务.一个进程的多个线程可以同时运行在不同的CPU上或多核CPU的不同内核上. 线 ...
- Cisco 三层交换机划分VLan与普通路由器连接配置
根据一些中小企业的一些业务需求,设计一套方案: 计划目标:针对不同部门划分不同的VLAN,前期满足能够同时上网的需求,后期需要能够隔离不同部门的资源访问(本次配置操作不涉及). 因之前未接触CISCO ...
- PhpMyAdmin提示未加密
新版本的PhpMyAdmin 增强了安全性,需要在配置文件设置一个短语密码.否则进入之后会有“配置文件现在需要一个短语密码.”的红色警叹提示. 解决方法: .将 phpMyAdmin/librarie ...
- Elasticsearch-数组和多字段
ES-数组和多字段 当需要在同一个字段中需要拥有多个值时,就会用到数组. 数组 如果要索引拥有多个值的字段,将这些值放入方括号中即可.在music索引下的album类型中,添加songs字段,存储专辑 ...
- [转帖]微软公布2019 Q2财报 几大部门均实现增长
微软公布2019 Q2财报 几大部门均实现增长 https://baijiahao.baidu.com/s?id=1624179330159140676&wfr=spider&for= ...