Closest Common Ancestors
Time Limit: 2000MS   Memory Limit: 10000K
Total Submissions: 18013   Accepted: 5774

Description

Write a program that takes as input a rooted tree and a list of pairs of vertices. For each pair (u,v) the program determines the closest common ancestor of u and v in the tree. The closest common ancestor of two nodes u and v is the node w that is an ancestor of both u and v and has the greatest depth in the tree. A node can be its own ancestor (for example in Figure 1 the ancestors of node 2 are 2 and 5)

Input

The data set, which is read from a the std input, starts with the tree description, in the form:

nr_of_vertices 
vertex:(nr_of_successors) successor1 successor2 ... successorn 
...
where vertices are represented as integers from 1 to n ( n <= 900 ). The tree description is followed by a list of pairs of vertices, in the form: 
nr_of_pairs 
(u v) (x y) ...

The input file contents several data sets (at least one). 
Note that white-spaces (tabs, spaces and line breaks) can be used freely in the input.

Output

For each common ancestor the program prints the ancestor and the number of pair for which it is an ancestor. The results are printed on the standard output on separate lines, in to the ascending order of the vertices, in the format: ancestor:times 
For example, for the following tree: 

Sample Input

5
5:(3) 1 4 2
1:(0)
4:(0)
2:(1) 3
3:(0)
6
(1 5) (1 4) (4 2)
(2 3)
(1 3) (4 3)

Sample Output

2:1
5:5
有向图求LCA,注意输入的处理。
有向图只有一个树根,利用并查集求树根。无向图中可选任意一点作树根,在dfs是比有向图多一个条件,详情见代码。
#include"cstdio"
#include"cstring"
#include"vector"
using namespace std;
const int MAXN=;
int V;
vector<int> G[MAXN];
int par[MAXN];
void prep()
{
for(int i=;i<=MAXN;i++)
{
par[i]=i;
}
}
int fnd(int x)
{
if(par[x]==x)
return x;
return par[x]=fnd(par[x]);
}
void unite(int father,int son)
{
par[son]=fnd(father);
}
int fa[MAXN],dep[MAXN];
void dfs(int u,int father,int d)
{
fa[u]=father,dep[u]=d;
for(int i=;i<G[u].size();i++)
dfs(G[u][i],u,d+);//在无向图中 需要加上 if(G[u][i]!=father)
}
int lca[MAXN];
int LCA(int u,int v)
{
while(dep[u]>dep[v]) u=fa[u];
while(dep[v]>dep[u]) v=fa[v];
while(u!=v)
{
u=fa[u];
v=fa[v];
}
return u;
}
int main()
{
while(scanf("%d",&V)!=EOF)
{
for(int i=;i<=V;i++) G[i].clear();
prep();
memset(lca,,sizeof(lca));
for(int i=;i<V;i++)
{
int u,t;
scanf("%d:(%d)",&u,&t);
while(t--)
{
int v;
scanf("%d",&v);
G[u].push_back(v);
unite(u,v);
}
}
int root=fnd();
dfs(root,-,);
int Q;
scanf("%d",&Q);
while(true)
{
char ch=getchar();
if(ch=='(')
{
int u,v;
scanf("%d %d",&u,&v);
int a=LCA(u,v);
lca[a]++;
Q--;
getchar();//不能丢,有开就有闭
}
if(Q==) break;
}
for(int i=;i<=V;i++)
{
if(lca[i]!=) printf("%d:%d\n",i,lca[i]);
}
}
return ;
}

tarjan+并查集离线算法

#include"cstdio"
#include"cstring"
#include"vector"
using namespace std;
const int MAXN=;
int V;
vector<int> G[MAXN];
int que[MAXN][MAXN];
int vis[MAXN];
int par[MAXN];
int cnt[MAXN];
void prep()
{
for(int i=;i<=MAXN;i++)
par[i]=i;
}
int fnd(int x)
{
if(par[x]==x)
return x;
return par[x]=fnd(par[x]);
}
void unite(int father,int son)
{
par[son]=fnd(father);
}
void dfs(int u)
{
for(int i=;i<=V;i++)
if(vis[i]&&que[u][i])
{
int fa=fnd(i);//fa 为u与i的LCA
cnt[fa]+=que[u][i];
}
vis[u]=;
for(int i=;i<G[u].size();i++)
{
int v=G[u][i];
dfs(v);
unite(u,v);
}
}
int indeg[MAXN];
int main()
{
while(scanf("%d",&V)!=EOF)
{
prep();
for(int i=;i<=V;i++) G[i].clear();
memset(que,,sizeof(que));
memset(vis,,sizeof(vis));
memset(cnt,,sizeof(cnt));
memset(indeg,,sizeof(indeg));
for(int i=;i<V;i++)
{
int u,t;
scanf("%d:(%d)",&u,&t);
while(t--)
{
int v;
scanf("%d",&v);
G[u].push_back(v);
indeg[v]++;
}
}
int Q;
scanf("%d",&Q);
while(Q--)
{
int u,v;
scanf(" (%d %d)",&u,&v);
que[u][v]++;
que[v][u]++;
}
for(int i=;i<=V;i++)
if(!indeg[i])//入度为0的点为根节点
{
dfs(i);
break;
}
for(int i=;i<=V;i++)
if(cnt[i]!=) printf("%d:%d\n",i,cnt[i]);
}
return ;
}

POJ(有向图求LCA)的更多相关文章

  1. POJ 1986:Distance Queries(倍增求LCA)

    http://poj.org/problem?id=1986 题意:给出一棵n个点m条边的树,还有q个询问,求树上两点的距离. 思路:这次学了一下倍增算法求LCA.模板. dp[i][j]代表第i个点 ...

  2. 树上倍增求LCA及例题

    先瞎扯几句 树上倍增的经典应用是求两个节点的LCA 当然它的作用不仅限于求LCA,还可以维护节点的很多信息 求LCA的方法除了倍增之外,还有树链剖分.离线tarjan ,这两种日后再讲(众人:其实是你 ...

  3. POJ 1330(LCA/倍增法模板)

    链接:http://poj.org/problem?id=1330 题意:q次询问求两个点u,v的LCA 思路:LCA模板题,首先找一下树的根,然后dfs预处理求LCA(u,v) AC代码: #inc ...

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

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

  5. 树链剖分求LCA

    树链剖分中各种数组的作用: siz[]数组,用来保存以x为根的子树节点个数 top[]数组,用来保存当前节点的所在链的顶端节点 son[]数组,用来保存重儿子 dep[]数组,用来保存当前节点的深度 ...

  6. 树上倍增求LCA(最近公共祖先)

    前几天做faebdc学长出的模拟题,第三题最后要倍增来优化,在学长的讲解下,尝试的学习和编了一下倍增求LCA(我能说我其他方法也大会吗?..) 倍增求LCA: father[i][j]表示节点i往上跳 ...

  7. [算法]树上倍增求LCA

    LCA指的是最近公共祖先(Least Common Ancestors),如下图所示: 4和5的LCA就是2 那怎么求呢?最粗暴的方法就是先dfs一次,处理出每个点的深度 然后把深度更深的那一个点(4 ...

  8. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  9. 【倍增】洛谷P3379 倍增求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

随机推荐

  1. Microsoft-office 常见问题

    1.工作表写入保护,忘记密码,解决办法: 流程如下: 1打开文件2工具---宏----录制新宏---输入名字如:aa3停止录制(这样得到一个空宏)4工具---宏----宏,选aa,点编辑按钮5删除窗口 ...

  2. Linux 批量替换的一种实现方式

    替换某目录下所有文件中的某个字符: sed -i 's/origin_str/new_str/g' `grep origin_str -rl ./` origin_str:被替换的字符串: new_s ...

  3. Unity3D研究院之拓展自定义编辑器窗口

    Unity支持自行创建窗口,也支持自定义窗口布局.在Project视图中创建一个Editor文件夹,在文件夹中在创建一条脚本. 自定义窗口需要让脚本继承EditorWindow在设置MenuItem, ...

  4. spring AOP(切面)

    AOP 基本概念cross  cutting concern横切性关注点:独立服务,遍布在系统处理流程之中 Aspect对横切关注点模块化 advice对横切关注点具体实现 pointcut定义adv ...

  5. 消息队列Handler的用法

    下面是每隔一段时间就执行某个操作,直到关闭定时操作: final Handler handler = new Handler(); Runnable runnable = new Runnable() ...

  6. 模块:(日期选择)jquery、bootstrap实现日期下拉选择+bootstrap jquery UI自带动画的日期选择器

    一:jquery.bootstrap实现日期下拉选择 点击文本框弹出窗口 弹窗显示日期时间选择下拉 年份取当前年份的前后各5年 天数随年份和月份的变化而变化 点击保存,文本框中显示选中的日期 代码部分 ...

  7. 计算机网络 --万维网www

    万维网是一个分布式的超媒体系统,客户程序向服务器程序发出请求,服务器程序向客户程序送回客户所需要的万维网文档.万维网必须解决的几个问题:1.怎样标志分布在整个因特网上的万维网文档?答:万维网使用统一的 ...

  8. 九度OJ 1168:字符串的查找删除 (查找)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:4276 解决:1699 题目描述: 给定一个短字符串(不含空格),再给定若干字符串,在这些字符串中删除所含有的短字符串. 输入: 输入只有1 ...

  9. Kafka核心思想

    Kafka是2010年12月份开源的项目,采用Scala语言编写,使用了多种效率优化机制,整体架构比较新颖(push/pull),更适合异构集群. 设计目标: (1) 数据在磁盘上的存取代价为O(1) ...

  10. spring运行步骤

    Spring确实使你能通过最简单可行的解决的方法来解决你的问题. 而这是有有非常大价值的.同一时候他的源码的设计理念也受到非常多程序猿的追捧,简洁,易用.但是从哪着手研究Spring却是非常多新手头疼 ...