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
Problem Description
  在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
  这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
  
  1.
CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
  2. CD ..
(返回当前目录的上级目录)
  
  现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
 
Input
输入数据第一行包含一个整数T(T<=20),表示样例个数;每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;接下来N-1行每行两个目录名A
B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。最后M行每行两个目录名A
B,表示询问将当前目录从A变成B最少要多少次CD操作。数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
 
Output
请输出每次询问的结果,每个查询的输出占一行。
 
Sample Input
2
3 1
B A
C A
B C

3 2
B A
C B
A C
C A

 
Sample Output
2
1
2
 
  1. 从父目录到任意一个子目录的距离都是1
  2. 用一个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 ;
}
 
Source
2013金山西山居创意游戏程序挑战赛——初赛(1)

HDU 4547 CD操作 (LCA最近公共祖先Tarjan模版)的更多相关文章

  1. LCA 最近公共祖先 tarjan离线 总结 结合3个例题

    在网上找了一些对tarjan算法解释较好的文章 并加入了自己的理解 LCA(Least Common Ancestor),顾名思义,是指在一棵树中,距离两个点最近的两者的公共节点.也就是说,在两个点通 ...

  2. LCA 最近公共祖先 Tarjan(离线)算法的基本思路及其算法实现

    首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖先节点,而最近公共祖先,就是两个节点在这棵树上深度最大的公共的祖先节点. 换句话说,就是两个点在这棵 ...

  3. LCA最近公共祖先——Tarjan模板

    LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. Tarjan是一种离线算法,时间复杂度O(n+Q),Q表示询问次数,其中 ...

  4. 【HDU 4547 CD操作】LCA问题 Tarjan算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4547 题意:模拟DOS下的cd命令,给出n个节点的目录树以及m次查询,每个查询包含一个当前目录cur和 ...

  5. HDU 4547 CD操作

    传送门 没啥好说的.就是一个LCA. 不过就是有从根到子树里任意一个节点只需要一次操作,特判一下LCA是不是等于v.相等的话不用走.否则就是1次操作. 主要是想写一下倍增的板子. 倍增基于二进制.暴力 ...

  6. LCA最近公共祖先 Tarjan离线算法

    学习博客:  http://noalgo.info/476.html 讲的很清楚! 对于一颗树,dfs遍历时,先向下遍历,并且用并查集维护当前节点和父节点的集合.这样如果关于当前节点(A)的关联节点( ...

  7. LCA(最近公共祖先)专题(不定期更新)

    Tarjan(离线)算法 思路: 1.任选一个点为根节点,从根节点开始. 2.遍历该点u所有子节点v,并标记这些子节点v已被访问过. 3.若是v还有子节点,返回2,否则下一步. 4.合并v到u上. 5 ...

  8. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载)

    Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)(转载) 转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2 ...

  9. lca 最近公共祖先

    http://poj.org/problem?id=1330 #include<cstdio> #include<cstring> #include<algorithm& ...

随机推荐

  1. SSH2 增删查改实例

    (一)引入包 (共73个,不一定都需要,但是我的项目是这么多,经过调试,没有包冲突) (二)创建数据库表 建立数据库octtest,并创建user表,表里面一共4个字段:id,姓,名,年龄. 语句如下 ...

  2. json-lib反序列化抽象属性及对象

    使用json默认反序列化接口反序列化对象时,对象的类型必须的确定的,比如不能是抽象类型,否则会报无法实例化对象的异常 如有下列类定义: public abstract class AbstracObj ...

  3. web项目在iis配置好后不能正确访问问题集锦,以及IIS常规设置

    6.IIS配置好,项目无法访问,注意项目对应的应用程序池的net版本是否正确,是否集成(一般都是集成,很少是经典) 本项目用的4.0,可IIS默认程序池为2.0,将2.0改为4.0就行.   7.HT ...

  4. 习题-第7章Web自动化测试

    一.选择题 1.如果火狐浏览器不在默认安装路径,编写Selenium的设置代码,横线处应该填入(    ), System.setProperty(“webdriver.firefox._______ ...

  5. ASP.NET Core 简单引入教程

    0.简介 开源.跨平台 1.环境安装 参考官方教程   Core 官方文档 2.向世界问个好 sheel/cmd 下: dotnet --help // 查看帮助 dotnet new *     / ...

  6. TCP与UDP(实时通讯)

    1.TCP使用 导入AsyncSocket资源文件夹,此文件是arc混编,加入库文件,如下图: #import "ViewController.h" #import "A ...

  7. L134

    这种成功和后来的研究(表明记忆本身并不是先天决定的)使爱立信总结到,记忆的行为与其说是一种习得的行为不如说是一种先天的行为. 这点我们不清楚-构思物体和找出数字模型的能力,回答问题(最好的诗人和哲学家 ...

  8. 浅析Java基本数据类型

    作为一种强类型语言,Java针对每一种数据都定义了明确的数据类型.大体来讲可分为:基本数据类型和引用数据类型:在此,主要讨论前者,后者以后再继续探究. Java基本数据类型分为四类八种: 1: 整数 ...

  9. 如何复制一个java对象(浅克隆与深度克隆)

    在项目中,有时候有一些比较重要的对象经常被当作参数传来传去,和C语言的值传递不同,java语言的传递都是引用传递,在任何一个地方修改了这个对象的值,就会导致这个对象在内存中的值被彻底改变.但是很多时候 ...

  10. Spring Boot打包总结

    环境配置信息 -** JDK 1.8 -** Spring Boot 1.5.3.RELEASE -** IDE: STS 3.4 Spring Boot下打包过程 基于STS创建Spring boo ...