HDU 4547 CD操作 (LCA最近公共祖先Tarjan模版)
CD操作
倍增法 https://i.cnblogs.com/EditPosts.aspx?postid=8605845
Time Limit : 10000/5000ms (Java/Other) Memory Limit : 65535/32768K (Java/Other)
Total Submission(s) : 4 Accepted Submission(s) : 3
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1.
CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD ..
(返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。最后M行每行两个目录名A
B,表示询问将当前目录从A变成B最少要多少次CD操作。数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
3 1
B A
C A
B C
3 2
B A
C B
A C
C A
1
2
- 从父目录到任意一个子目录的距离都是1
- 用一个flag记录一下询问是从左到右还是从右到左,有几种情况
- 左边是右边的父亲,距离为1
- 右边是左边的父亲,距离是dis[v]到lca(u,v)
- 其他情况+1
其他就是离线求Tarjan的lca了
- #include<iostream>
- #include <cstring>
- #include <string>
- #include <algorithm>
- #include <map>
- using namespace std;
- typedef long long ll;
- #define inf 1000000
- #define mem(a,b) memset(a,b,sizeof(a))
- const int N=+;
- const int M=*N;
- int pre[N],first[N],first2[N],tot,tot2;
- bool vis[N];//标记有没有询问
- int n;
- int fa[N],ans[N],cnt;
- int vis2[N],dis[N];
- map<string,int>m;
- struct edge
- {
- int v,next;
- } e[M];
- struct Query
- {
- int v,next,id,flag;//flag用来标记是从左到右还是从到左
- } query[M];
- void add(int u,int v)
- {
- e[tot].v=v;
- e[tot].next =first[u];
- first[u]=tot++;
- }
- void dfs(int u,int len)//建立深度
- {
- vis2[u]=;
- dis[u]=len;
- for(int i=first[u];~i;i=e[i].next)
- {
- int v=e[i].v;
- if(!vis2[v])
- dfs(v,len+);
- }
- }
- void add_query(int u,int v,int id,int flag)//建立询问的边
- {
- query[tot2].flag =flag;
- query[tot2].id=id;
- query[tot2].v=v;
- query[tot2].next=first2[u];
- first2[u]=tot2++;
- }
- int find(int x)
- {
- return x==pre[x]?x:pre[x]=find(pre[x]);
- }
- void lca(int u,int fa)//Targin算法
- {
- for(int i=first[u];~i;i=e[i].next)
- {
- int v=e[i].v;
- if(v==fa) continue;
- lca(v,u);
- pre[v]=u;
- }
- vis[u]=;
- for(int i=first2[u];~i;i=query[i].next)
- {
- int v=query[i].v;
- if(vis[v])//那么find(v)就是最近公共祖先
- {
- int id=query[i].id;
- int flag=query[i].flag ;
- if(flag==)
- {
- if(u==find(v))
- {
- ans[id]=;//直接跃上找到父目录
- }
- else if(find(u)==v)
- ans[id]=dis[u]-dis[find(v)];//向下走找到目标目录
- else
- ans[id]=dis[u]-dis[find(v)]+;//一个越到父目录,再向下找
- }
- else//
- {
- int u1=v;
- int v1=u;
- if(u1==find(v1))
- ans[id]=;
- else if(find(u1)==v1)
- ans[id]=dis[u1]-dis[find(v)];
- else
- ans[id]=dis[u1]-dis[find(v)]+;
- }
- }
- }
- }
- void init()
- {
- mem(first,-);
- mem(first2,-);
- mem(vis,);
- mem(vis2,);
- mem(fa,-);
- mem(ans,);
- tot=;
- tot2=;
- cnt=;
- m.clear();
- for(int i=; i<=n; i++)
- pre[i]=i;
- }
- struct node
- {
- int u,v;
- } zz[N];
- int main()
- {
- int t,mm;
- string s1,s2;
- scanf("%d",&t);
- while(t--)
- {
- scanf("%d%d",&n,&mm);
- init();
- for(int i=; i<n; i++)
- {
- cin>>s1>>s2;
- if(!m[s1]) m[s1]=cnt++;
- if(!m[s2]) m[s2]=cnt++;
- int a=m[s1],b=m[s2];
- add(a,b);
- add(b,a);
- fa[a]=b;
- }
- int root=;
- while(~fa[root]) root=fa[root];
- dfs(root,);
- for(int i=; i<=mm; i++)
- {
- cin>>s1>>s2;
- int a=m[s1],b=m[s2];
- zz[i].u=a,zz[i].v=b;
- add_query(a,b,i,);
- add_query(b,a,i,);
- }
- lca(root,root);
- for(int i=; i<=mm; i++)
- {
- int u=zz[i].u,v=zz[i].v;
- if(u==v)
- puts("");
- else
- printf("%d\n",ans[i]);
- }
- }
- return ;
- }
HDU 4547 CD操作 (LCA最近公共祖先Tarjan模版)的更多相关文章
- LCA 最近公共祖先 tarjan离线 总结 结合3个例题
在网上找了一些对tarjan算法解释较好的文章 并加入了自己的理解 LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通 ...
- LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现
首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点. 换句话说,就是两个点在这棵 ...
- LCA最近公共祖先——Tarjan模板
LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. Tarjan是一种离线算法,时间复杂度O(n+Q),Q表示询问次数,其中 ...
- 【HDU 4547 CD操作】LCA问题 Tarjan算法
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和 ...
- HDU 4547 CD操作
传送门 没啥好说的.就是一个LCA. 不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v.相等的话不用走.否则就是1次操作. 主要是想写一下倍增的板子. 倍增基于二进制.暴力 ...
- LCA最近公共祖先 Tarjan离线算法
学习博客: http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点( ...
- LCA(最近公共祖先)专题(不定期更新)
Tarjan(离线)算法 思路: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5 ...
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)
Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...
- lca 最近公共祖先
http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...
随机推荐
- XP_SP3_专业汉化版__x86_cd_x14-80404
1.镜像文件: zh-hans_windows_xp_professional_with_service_pack_3_x86_cd_x14-80404.iso 来自 msdn itellyou 2. ...
- istringstream 用法
istringstream 类用于执行C++风格的串流的输入操作 istringstream用空格作为字符串分隔符 #include <iostream>#include <sstr ...
- 智课雅思词汇---二十三、名词性后缀mony
智课雅思词汇---二十三.名词性后缀mony 一.总结 一句话总结:Latin: action, result of an action or condition; a suffix that for ...
- Microsoft Edge Certified with EBS 12.1 and 12.2
I am very pleased to announce that Microsoft Edge is certified as a new browser for Oracle E-Busines ...
- openvswitch的原理和常用命令
一.Openvswitch工作原理 openvSwitch是一个高质量的.多层虚拟交换机,使用开源Apache2.0许可协议,由 Nicira Networks开发,主要实现代码为可移植的C代码.它的 ...
- MySQL 实践
一.下载MySQL 1.mysql-noinstall-5.1.73-win32.zip 2.mysql-connector-net-6.8.3.msi 二.安装MySQL 三.连接MySQL 1.A ...
- LeetCode OJ:Set Matrix Zeroes(设置矩阵0元素)
Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place. 这题要注意的 ...
- String、StringBuffer、StringBuilder分析(jdk8)
以下代码只挑选了关键方法进行分析 public final class String //String类不可继承,实现了序列化 implements java.io.Serializable, Com ...
- Agilent RF fundamentals (11)-Vector modulator
Vector modulator 矢量调制器:调整信号的幅度和相位 http://www.21ic.com/app/test/201805/762401.htm
- 如何在100万文字的文章中 200ms内 快速提取 替换 上万个关键字
关键点: 关键字 组合 成一棵 hash 树 ( 有属性就直接移动指针到下一个字对象, 没有属性就创建子对象, 再移动指针; 第二次循环在子对象看有没这个属性 ) 探测针 标记结束 ...