在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
提示:
普通的方法会T。
离线算法:一开始就知道所有问题的输入数据,在解决问题后立即输出。
思路:
1. 建树
2.dfs一遍,找出所有节点到根节点的距离。
3.tarjan+并查集。比如找<u,v>的LCA,回溯到u节点的时候,如果发现v节点在搜索过的小树中,那么<u,v>的LCA等于
find(v)。如果不在小树中,则不用理会,等下一次搜索到v节点的时候再找<v,u>的LCA。(两个的最近公共祖先相同)。
LCA算法博客:https://blog.youkuaiyun.com/csyzcyj/article/details/10051173
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<iostream>
#define M 100010
#include<map>
using namespace std;
map<string,int>mp;
int t,n,m,x,y,carry,tot,tBt,root;
int headA[M],headB[M],in[M],d[M],vis[M],fa[M];
string a,b;
struct path
{
int to,nextt,num;
}A[M],B[M*2];
struct node
{
int x,y,lca;
}C[M];
int re_str(string str)
{
if(!mp[str])
mp[str]=++carry;
return mp[str];
}
void init()
{
mp.clear();
carry=tot=tBt=0;
memset(headA,-1,sizeof(headA));
memset(headB,-1,sizeof(headB));
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
for(int i=1;i<=n;i++)
fa[i]=i;
}
void addA(int u,int v,int w)
{
A[tot].to=v;
A[tot].num=w;
A[tot].nextt=headA[u];
headA[u]=tot++;
}
void addB(int u,int v,int w)
{
B[tBt].to=v;
B[tBt].num=w;
B[tBt].nextt=headB[u];
headB[u]=tBt++;
}
void dfs(int u,int k)
{
int tem;
d[u]=k;
for(int i=headA[u];i!=-1;i=A[i].nextt)
{
tem=A[i].to;
dfs(tem,k+1);
}
}
int Find(int x)
{
if(fa[x]!=x) fa[x]=Find(fa[x]);
return fa[x];
}
void tarjan(int u)
{
int tem;
vis[u]=true;
fa[u]=u;
for(int i=headA[u];i!=-1;i=A[i].nextt)
{
tem=A[i].to;
tarjan(tem);
fa[tem]=u;
}
for(int i=headB[u];i!=-1;i=B[i].nextt)
{
tem=B[i].to;
if(vis[tem]==true)
{
C[B[i].num].lca=Find(tem);
}
}
}
void slove()
{
int ans,fal;
for(int i=1;i<=m;i++)
{
x=C[i].x;
fal=C[i].lca;
ans=d[x]-d[fal];
if(fal!=C[i].y)
ans++;
printf("%d\n",ans);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
init();
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
{
cin>>a;
cin>>b;
x=re_str(a);
y=re_str(b);
addA(y,x,-1);
in[x]++;
}
for(int i=1;i<=m;i++)
{
cin>>a;
cin>>b;
x=re_str(a);
y=re_str(b);
addB(x,y,i);
addB(y,x,i);
C[i].x=x;
C[i].y=y;
}
for(int i=1;i<=n;i++)
{
if(in[i]==0)
{
root=i;
break;
}
}
dfs(root,1);
tarjan(root);
slove();
}
}