【HDU 4547 CD操作】LCA问题 Tarjan算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547
题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和一个目标目录tar,返回从cur切换到tar所要使用的cd命令次数:
注意这里的cd命令是简化版,只能进行如下两种操作:
1. cd .. //返回父目录
2. cd cur\一系列目录\tar //由当前目录跳转到目标目录,注意中间的“一系列目录”不能包含父目录..,也就是说,自底向上必须一步步走,而自顶向下可以一步到位。
思路:用Tarjan算法求LCA,处理查询时要分类讨论:
1. if tar == lca,则res(cur, tar) = depth(cur) - depth(lca); (包含tar == cur的情况)
2. else if cur == lca, 则res(cur, tar) = 1;
3. 其他,则res(cur, tar) = depth(cur) - depth(lca) + 1;
这道题还有些细节问题需要处理好:
1. 每个查询要记录好目标目录是谁。因为tarjan算法是批处理的,即每完成对一个棵子树的遍历,处理其树根所涉及到的查询。为使查询处理不遗漏,我们把查询也以邻接表的形式存成双向边,然而每次处理需要知道本次查询原始的“单向边”,这样才能根据上面的分类计算结果。所以我另设了一个数组ans_tar[i]记录第 i 个查询所给定的tar。
2. 同HDU2586这道题,多个查询,注意记录查询序列号。这道题我用邻接表项query_id[r][i]记录节点r的第i个查询所持有的查询序列号,用邻接表项query_tar[r][i]记录节点r的第i个查询的目标节点。
3. 给出的目录是字符串,要用一个map<string, int>存储名称到节点号的映射关系。
这里又了解到了map一个用法,即对[]的重载:对于map<string, int> m,如果调用一次m[s],而s在m中不存在时,会自动插入s并将它的value置为0。这个设计对于这道题很合适,可以维护全局计数变量seq_num,如果返回0的话,分发下一个序号给它即可。
#include <cstdio>
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <cstring>
using namespace std;
const int MAX_N = ;
const int MAX_M = ; int vis[MAX_N];
int ans[MAX_N];
int ans_tar[MAX_N];//每组查询的目标目录
int indeg[MAX_N];
int depth[MAX_N];
map<string, int> name;
vector<int> G[MAX_N];//邻接表,边不带权
vector<int> query_tar[MAX_N];
vector<int> query_id[MAX_N];
int par[MAX_N]; int T;
int n, m;
int seq_num;//目录名的序列号,从1开始 void init(){
seq_num = ;
memset(vis, , sizeof(vis));
memset(ans, , sizeof(ans));
memset(ans_tar, , sizeof(ans_tar));
memset(indeg, , sizeof(indeg));
memset(depth, , sizeof(depth));
name.clear();
for(int i=; i<MAX_N; i++){
G[i].clear();
query_tar[i].clear();
query_id[i].clear();
par[i] = i;
}
}
int find(int x){
return par[x]==x ? x : 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){
//cout << "dfs " << r << endl;
vis[r] = ;
depth[r] = l;
for(int i=; i<G[r].size(); i++){
//cout << G[r][i] << endl;
if(vis[G[r][i]]) continue;
dfs(G[r][i], l+);
unite(r, G[r][i]);
}
for(int i=; i<query_tar[r].size(); i++){
if(!vis[query_tar[r][i]]) continue;
int cur, tar;
int ans_id = query_id[r][i];//这一查询所持的序列号
int real_tar = ans_tar[ans_id];//这一个查询真正指定的target
if(r == real_tar){//当前r是目标
cur = query_tar[r][i];
tar = real_tar;
}else{//已访问过的那个点是目标
cur = r;
tar = real_tar;
}
//cout << "query " << cur << tar << endl;
int ca = find(query_tar[r][i]);
if(tar == ca) ans[ans_id] = depth[cur] - depth[ca];
else if(cur == ca) ans[ans_id] = ;
else ans[ans_id] = depth[cur] - depth[ca] + ;
}
} void lca(int r){
//cout << "root " << r << endl;
dfs(r, );
} int main()
{
freopen("4547.txt", "r", stdin);
scanf("%d", &T);
while(T--){
init();
scanf("%d%d", &n, &m);
for(int i=; i<n-; i++){
string c, p;
cin>>c;
int u = name[c];//不存在会自动插入并置value为0
if(u==){
u = name[c] = seq_num++;
} cin>>p;
int v = name[p];
if(v==){
v = name[p] = seq_num++;
}
G[u].push_back(v);
G[v].push_back(u);
indeg[u]++;//入度为0的是根目录
}
// for(map<string, int>::iterator iter = name.begin();
// iter != name.end(); iter++){
// cout << iter->first << iter->second << endl;
// }
for(int i=; i<m; i++){
string cur, tar;
cin >> cur >> tar;
int u = name[cur];
int v = name[tar];
query_tar[u].push_back(v);
query_tar[v].push_back(u);
query_id[u].push_back(i);//tar和id是同步记录的
query_id[v].push_back(i);
ans_tar[i] = v;//为辨谁是目标目录
}
for(map<string, int>::iterator iter = name.begin();
iter != name.end(); iter++){
int id = iter->second;
if(indeg[id] == ){
lca(id);
break;
}
}
for(int i=; i<m; i++){
printf("%d\n", ans[i]);
}
}
return ;
}
【HDU 4547 CD操作】LCA问题 Tarjan算法的更多相关文章
- HDU 4547 CD操作 (LCA最近公共祖先Tarjan模版)
CD操作 倍增法 https://i.cnblogs.com/EditPosts.aspx?postid=8605845 Time Limit : 10000/5000ms (Java/Other) ...
- HDU 4547 CD操作
传送门 没啥好说的.就是一个LCA. 不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v.相等的话不用走.否则就是1次操作. 主要是想写一下倍增的板子. 倍增基于二进制.暴力 ...
- 【HDU 2586 How far away?】LCA问题 Tarjan算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586 题意:给出一棵n个节点的无根树,每条边有各自的权值.给出m个查询,对于每条查询返回节点u到v的最 ...
- 【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) ...
- 近期公共祖先(LCA)——离线Tarjan算法+并查集优化
一. 离线Tarjan算法 LCA问题(lowest common ancestors):在一个有根树T中.两个节点和 e&sig=3136f1d5fcf75709d9ac882bd8cfe0 ...
- 最近公共祖先(LCA)---tarjan算法
LCA(最近公共祖先).....可惜我只会用tarjan去做 真心感觉tarjan算法要比倍增算法要好理解的多,可能是我脑子笨吧略略略 最近公共祖先概念:在一棵无环的树上寻找两个点在这棵树上深度最大的 ...
- 【POJ 1330 Nearest Common Ancestors】LCA问题 Tarjan算法
题目链接:http://poj.org/problem?id=1330 题意:给定一个n个节点的有根树,以及树中的两个节点u,v,求u,v的最近公共祖先. 数据范围:n [2, 10000] 思路:从 ...
- LCA(Tarjan算法)模板
一.查询一组的LCA Nearest Common Ancestors A rooted tree is a well-known data structure in computer science ...
- Tarjan 算法求 LCA / Tarjan 算法求强连通分量
[时光蒸汽喵带你做专题]最近公共祖先 LCA (Lowest Common Ancestors)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili tarjan LCA - YouTube Tarj ...
随机推荐
- 精确覆盖DLX算法模板
代码 struct DLX { int n,id; int L[maxn],R[maxn],U[maxn],D[maxn]; ]; ) //传列长 { n=nn; ;i<=n;i++) U[i] ...
- GIT入门篇-基本概念与操作
GIT 首先必须说明的是, 这篇文章不是阐述GIT原理性和比较深入的文章.只是对于日常开发中比较常用的需求的总结和GIT这些命令大体的原理解释.所以掌握这个只能说能够应付一定的开发需求.但是如果你是个 ...
- qt model/view 架构自定义模型之QStringListModel
# -*- coding: utf-8 -*- # python:2.x #QStringListModel #QStringListModel 是最简单的模型类,具备向视图提供字符串数据的能力. # ...
- Java连接Oracle数据库的示例代码
最基本的Oracle数据库连接代码(只针对Oracle11g): 1.右键项目->构建路径 ->配置构建路径,选择第三项“库”,然后点击“添加外部Jar”,选择 “D:\Oracle\ap ...
- kafka与Spring的集成
准备工作 kafka版本:kafka_2.10-0.10.1.0 spring版本:spring4.3 配置文件 pom文件配置(也可以直接下载jar包) Kafka和spring集成的支持类库,sp ...
- Oracle—RMAN备份(二)
在Oracle RMAN备份(一)中,对各种文件在RMAN中备份进行了说明, 一.备份集的复制 在RMAN 备份中,可以备份其自己的备份,即备份一个文件放在多个目录下,oralce支持最多备份四个. ...
- [IDEA学习笔记][keymap]
一个总站: http://www.youmeek.com/ 常用的快捷键keymap 提示: ctrl+N:快速打开一个类 Ctrl+P 方法参数提示显示 Ctrl+J 提示自定义模板 Ctrl+O ...
- EffectiveC#03--用委托表示回调,用事件定义对外接口
1.回调的场景:我给了儿子一个任务且他可以报告状态来(重复的)打断我.而我在等待他完成任务的每一个部份时不用阻塞我自己的进程.他可以在有重要(或者事件)状态报告时,可以定时的打断我,或者向我询求帮助 ...
- GridView控件中插入自定义删除按钮并弹出确认框
GridView控件中插入自定义删除按钮,要实现这个功能其实有多种方法,这里先记下我使用的方法,以后再添加其他方法. 一.实现步骤 1.在GridView中添加模板列(TemplateField). ...
- 8、Khala的设备间管理+通信
在之前的文档中,我们都是从单个设备的角度进行介绍,但在实际业务中,不同设备间存在交互行为.我们经常需要在一个设备的生命周期中查询另一个设备信息,或者向另一个设备进行通信.因此我们提供了设备管理模块来对 ...