CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 458 Accepted Submission(s): 126
Problem Description
在Windows下我们可以通过cmd运行DOS的部分功能,其中CD是一条很有意思的命令,通过CD操作,我们可以改变当前目录。
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. 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操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
每个样例首先一行是两个整数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
具体思路就是找到查询的公共祖先。如果他们祖先是起点,那么直接一次CD,如果公共祖先是终点那么结果是高度差,如果起点和重点一样,那么为0,其他情况是先用起点和公共祖先的高度差步数走到最进公共祖先,然后再一次CD达到目的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
map<string,int> mp;
int n,m,idx,root,ne,ne1;
int pre[100010];
int deep[100010];
int income[100010];
int head[100010];
int head1[200010];
struct mnode
{
int u,v,next;
}edge[100010];
struct qnode
{
int u,v,Ans,next;
}edge1[200010];
void add(int u,int v)
{
edge[ne].u=u,edge[ne].v=v,edge[ne].next=head[u],head[u]=ne++;
}
void add1(int u,int v)
{
edge1[ne1].u=u,edge1[ne1].v=v,edge1[ne1].next=head1[u],head1[u]=ne1++;
edge1[ne1].u=v,edge1[ne1].v=u,edge1[ne1].next=head1[v],head1[v]=ne1++;
}
int findx(int x)
{
return pre[x]=(pre[x]==x?x:findx(pre[x]));
}
void Unicon(int u,int v)
{
pre[findx(v)]=findx(u);
}
void init()
{
idx=1;
ne=0;
ne1=0;
mp.clear();
for (int i=1;i<=n;i++)
{
head[i]=-1;head1[i]=-1;
pre[i]=-1;
income[i]=0;
}
}
void dfs(int u,int dep)
{
int i,v;
deep[u]=dep;
pre[u]=u;
for (i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].v;
if (pre[v]==-1)
{
dfs(v,dep+1);
Unicon(u,v);
}
}
for (i=head1[u];i!=-1;i=edge1[i].next)
{
v=edge1[i].v;
if (pre[v]!=-1) edge1[i].Ans=edge1[i^1].Ans=findx(v);
}
}
int main()
{
int t,i,ss,tt;
char name1[50],name2[50];
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
for (i=1;i<n;i++)
{
scanf("%s%s",name1,name2);
if (!mp[name1]) mp[name1]=idx++;
if (!mp[name2]) mp[name2]=idx++;
income[mp[name1]]++;
add(mp[name2],mp[name1]);
}
for (i=1;i<idx;i++) if (income[i]==0) {root=i;break;}
for (i=1;i<=m;i++)
{
scanf("%s%s",name1,name2);
ss=mp[name1],tt=mp[name2];
add1(ss,tt);
}
dfs(root,0);
for (i=0;i<ne1;i+=2)
{
if (edge1[i].u==edge1[i].v) puts("0");
else if (edge1[i].Ans==edge1[i].u) puts("1");
else if (edge1[i].Ans==edge1[i].v)
printf("%d\n",deep[edge1[i].u]-deep[edge1[i].v]);
else
printf("%d\n",deep[edge1[i].u]-deep[edge1[i].Ans]+1);
}
}
return 0;
}