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
Source
1:这道题树上面的信息是字符串,而不是单个字母。 2:使用LCA来做的话,当n=1的时候,查询A B的时候答案应该是0,而不是1. 3:容器要清空!!!字符要初始化!!! 4:因为查询是从u到v,所以当u是祖先节点的时候,直接输出1就是了。 当查询的两个点是同一个点以及n==1的时候,输出0。 当v是祖先节点的时候,输出结果为abs(u的深度-v的深度) 当u和v都不是祖先节点的时候,输出结果为abs(u的深度-祖先节点的深度)+1 |
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<string.h>
#include<string>
using namespace std;
const int maxn=1e5+10;
const int DEG=20;
int head[maxn],tot,top;
int fa[maxn][DEG],depth[maxn];
bool flag[maxn];
int father[maxn];
int n,m;
int number;
char x[50],y[50];
map<string,int>mpp;
struct Edge
{
int to,next;
} edge[maxn*2];
struct xiao
{
int u,w;
} mapp[maxn];
bool cmp(xiao a,xiao b)
{
return a.u<b.u;
}
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void debug()
{
cout<<"____5_____"<<endl;
}
void init()
{
mpp.clear();
number=1;
tot=0;
memset(head,-1,sizeof(head));
memset(flag,false,sizeof(flag));
memset(depth,0,sizeof(depth));
memset(fa,0,sizeof(fa));
}
void BFS(int root)
{
queue<int>que;
depth[root]=0;
fa[root][0]=root;
que.push(root);
while(!que.empty())
{
int tmp=que.front();
que.pop();
for(int i=1; i<DEG; ++i)
{
fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
}
for(int i=head[tmp]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[tmp][0])
continue;
depth[v]=depth[tmp]+1;
fa[v][0]=tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(depth[u]>depth[v])
{
int x=u;
u=v;
v=x;
}
int hu=depth[u],hv=depth[v];
int tu=u,tv=v;
for(int det=hv-hu,i=0; det; det>>=1,i++)
if(det&1)
tv=fa[tv][i];
if(tu==tv)
return tu;
for(int i=DEG-1; i>=0; --i)
{
if(fa[tu][i]==fa[tv][i])
continue;
tu=fa[tu][i];
tv=fa[tv][i];
}
return fa[tu][0];
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<n;++i)
{
scanf("%s%s",x,y);
int u,v;
if(mpp[x]) //代表存在过了
v=mpp[x];
else
{
mpp[x]=number++;
v=mpp[x];
}
if(mpp[y]) //代表存在过了
u=mpp[y];
else
{
mpp[y]=number++;
u=mpp[y];
}
addedge(u,v);
addedge(v,u);
flag[v]=true;
}
int root=1;
for(int i=1;i<=n;++i)
{
if(!flag[i])
{
root=i;
break;
}
}
BFS(root);
while(m--)
{
scanf("%s%s",x,y);
int u=mpp[x];
int v=mpp[y];
int ancester=LCA(u,v);
int puts=0;
if(u==v||n==1) puts=0;
else if(ancester==u&&ancester!=v) puts=1;
else if(ancester==v&&ancester!=u) puts=abs(depth[u]-depth[v]);
else if(ancester!=v&&ancester!=u) puts=abs(depth[u]-depth[ancester])+1;
cout<<puts<<endl;
}
}
return 0;
}