【HDU 2586 How far away?】LCA问题 Tarjan算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题意:给出一棵n个节点的无根树,每条边有各自的权值。给出m个查询,对于每条查询返回节点u到v的最短路径的权值和,按查询顺序输出结果。
数据范围:n [2, 40000], m[1, 200]
思路:Tarjan算法:dfs遍历每个点,每遍历完 r 的一个孩子 c, 把 c 并入以 r 为祖先的集合,并处理 c 的所有查询 q:若qi的目标节点 v 已被遍历到,那么一定有lca(c, v) = find(v)。
具体实现上,需要记录这样几个信息:每个节点的深度depth、邻接表G、访问标记vis。
对于每组查询(u, v)时,可用这个公式得到结果res(u, v) = depth(u) - depth(lca(u,v)) + depth(v) - depth(lca(u,v))。
注意Tarjan算法是脱机的(离线的)、批处理的,即其查询结果的生成顺序与最初的查询输入顺序无关。因此需要将乱序生成的结果合理组织以实现顺序输出。这一点我没有想好怎么做,下面的实现是参照了到网上他人的代码。具体方法就是:用类似记录查询目标节点的方法去记录查询序号,即query[r][i]存的是第r个节点的第i个查询所涉及的目标节点,类似地,num[r][i]存的是第r个节点的第i个查询在输入查询序列中的序号。再附加一个ans[i]存储第i条查询的结果。这样每处理一个查询,即可把结果存入ans[num[r][i]] = res(r, i)
p.s 注意题目描述:没有说节点的序号分布在1...n,而我们的vis, query, depth等数组都是以下标标识节点号访问的。所以每次初始化时注意覆盖到整个区间[1, MAX_N]。这题n<=40000不是很大,若超过数组能开的最大长度,则需要“离散化”。
还有一点就是,这个问题只要使用深度优先遍历策略,左根右三个节点的访问顺序是没有关系的。因此可以借助先序遍历先访问根节点的便利,先修改vis数组,后遍历其邻接表,从而避免因邻接表存了双向边而出现“兜圈子”的情况。
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int MAX_N = ;
const int MAX_M = ; int T;
int n, m;
struct Edge{
int to, cost;
Edge(){}
Edge(int t, int c):to(t), cost(c){}
};
vector<Edge> G[MAX_N];
vector<int> query[MAX_N];
int vis[MAX_N];
vector<int> num[MAX_N];
int par[MAX_N];
int ans[MAX_M];
int depth[MAX_N]; void init(){
memset(vis, , sizeof(vis));
memset(ans, , sizeof(ans));
memset(depth, , sizeof(depth));
for(int i=; i<MAX_N; i++){
par[i] = i;
G[i].clear();
num[i].clear();
query[i].clear();
}
}
int find(int x){
if(par[x] == x) return x;
return par[x] = find(par[x]);
}
void unite(int x, int y){
x = find(x);
y = find(y);
if(x == y) return ;
par[y] = x;
} void dfs(int r, int l){
vis[r] = ;//先序遍历
depth[r] = l;
for(int i=; i<G[r].size(); i++){
if(!vis[G[r][i].to]){
dfs(G[r][i].to, l+G[r][i].cost);
unite(r, G[r][i].to);
}
}
for(int i=; i<query[r].size(); i++){
if(vis[query[r][i]]){//r的第i个查询的目标节点
int ca = find(query[r][i]);
ans[num[r][i]] = depth[r] + depth[query[r][i]] - depth[ca] - depth[ca];
//r的第i个查询所持有的查询号
}
}
} void lca(int r){
dfs(r, );
} int main()
{
//freopen("2586.txt", "r", stdin);
scanf("%d", &T);
while(T--){
init();
scanf("%d%d", &n, &m);
for(int i=; i<n-; i++){
int u, v, c;
scanf("%d%d%d", &u, &v, &c);
G[u].push_back(Edge(v, c));
G[v].push_back(Edge(u, c));
}
for(int i=; i<m; i++){
int u, v;
scanf("%d%d", &u, &v);
query[u].push_back(v);
query[v].push_back(u);
num[u].push_back(i);//u的下一个查询号插入向量num[u]
num[v].push_back(i);
}
lca();
for(int i=; i<m; i++){
printf("%d\n", ans[i]);
}
// for(int i=1; i<=n; i++){
// for(int j=0; j<G[i].size(); j++){
// printf("%d %d %d\n", i, G[i][j].to, G[i][j].cost);
// }
// }
}
return ;
}
【HDU 2586 How far away?】LCA问题 Tarjan算法的更多相关文章
- 【HDU 4547 CD操作】LCA问题 Tarjan算法
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和 ...
 - TTTTTTTTTTTTTTTTT         HDU  2586  How far away     LCA的离线算法   Tarjan
		
链接: How far away ? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Other ...
 - 【37.48%】【hdu 2587】How far away ?(3篇文章,3种做法,LCA之Tarjan算法)
		
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...
 - 【POJ 1330 Nearest Common Ancestors】LCA问题 Tarjan算法
		
题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从 ...
 - 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
		
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
 - 最近公共祖先(LCA)---tarjan算法
		
LCA(最近公共祖先).....可惜我只会用tarjan去做 真心感觉tarjan算法要比倍增算法要好理解的多,可能是我脑子笨吧略略略 最近公共祖先概念:在一棵无环的树上寻找两个点在这棵树上深度最大的 ...
 - 【强联通图 | 强联通分量】HDU 1269 迷宫城堡 【Kosaraju或Tarjan算法】
		
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明 ...
 - hdu 2586(最近公共祖先LCA)
		
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 思路:在求解最近公共祖先的问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好 ...
 - HDU 3078:Network(LCA之tarjan)
		
http://acm.hdu.edu.cn/showproblem.php?pid=3078 题意:给出n个点n-1条边m个询问,每个点有个权值,询问中有k,u,v,当k = 0的情况是将u的权值修改 ...
 
随机推荐
- 【CF 189A Cut Ribbon】dp
			
题目链接:http://codeforces.com/problemset/problem/189/A 题意:一个长度为n的纸带,允许切割若干次,每次切下的长度只能是{a, b, c}之一.问最多能切 ...
 - 《Java程序员面试笔试宝典》终于在万众期待中出版啦~
			
<Java程序员面试笔试宝典>终于在万众期待中出版啦~它是知名畅销书<程序员面试笔试宝典>的姊妹篇,而定价只要48元哦,恰逢求职季节,希望本书的出版能够让更多的求职者能够走进理 ...
 - poj 3045 Cow Acrobats(二分搜索?)
			
Description Farmer John's N (1 <= N <= 50,000) cows (numbered 1..N) are planning to run away a ...
 - jqGrid源代码分析(一)
			
废话少说.先上grid.base.js 整体结构图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvc3B5MTk4ODEyMDE=/font/5a6L5L2 ...
 - java RMI入门指南
			
感觉这篇文章不错,直接转了 RMI全称是Remote Method Invocation-远程方法调用,Java RMI在JDK1.1中实现的,其威力就体如今它强大的开发分布式网络应用的能力上,是纯J ...
 - Android日志系统Logcat源代码简要分析
			
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6606957 在前面两篇文章Android日志系 ...
 - Android-------设置TextView同时显示图片和文本,并控制图片大小
			
//获取资源图片 Drawable leftDrawable = getResources().getDrawable(R.drawable.comment_parise); //设置 ...
 - mssql 判断sql语句的执行效率语句
			
SET STATISTICS io ONSET STATISTICS time ONgo--========此处为sql代码段=============== select zxbh from t_yr ...
 - PL/SQL 流程控制语句-条件结构,循环结构
			
条件结构 一.IF-THEN语句 IF-THEN语句是最简单的IF语句. 语法: IF condition THEN Statements END IF; 例子: declare v_score nu ...
 - 1217.1——OC准备
			
#import 与 #include区别 include完成头文件的导入,可能会导致头文件的相互引用和函数或变量的重复定义 为了解决这个问题 我们必须这样做 #ifndef Student_h #de ...