CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 799 Accepted Submission(s): 224
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
题意较裸,以前太弱,不会,最近做一下。
代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<string.h>
#include<string>
#include<map>
#include<string>
#include<queue>
#include<set>
using namespace std;
const int maxn=111111;
const int DEG=22;
struct node
{
int next,to;
}edge[maxn*2];
int head[maxn],tol,m,n;
void add(int u,int v)
{
edge[tol].to=v;
edge[tol].next=head[u];
head[u]=tol++;
}
void init()
{
memset(head,-1,sizeof(head));
tol=0;
}
int fa[maxn][DEG];
int deg[maxn];
void bfs(int root)
{
queue<int> q;
deg[root]=0;
fa[root][0]=root;
q.push(root);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=1;i<DEG;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa[u][0])continue;
deg[v]=deg[u]+1;
fa[v][0]=u;
q.push(v);
}
}
}
int lca(int u,int v)
{
if(deg[u]>deg[v])swap(u,v);
int hu=deg[u],hv=deg[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];
}
bool flag[maxn];
int cnt;
map<string,int> mp;
int find(char *str)
{
if(mp.find(str)!=mp.end())return mp[str];
mp[str]=++cnt;
return cnt;
}
int main()
{
int i,j,k,T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
init();
memset(flag,0,sizeof(flag));
cnt=0;
mp.clear();
char str1[1000],str2[1000];
for( i=1;i<n;i++)
{
scanf("%s%s",str1,str2);
j=find(str1);
k=find(str2);
add(k,j);
flag[j]=1;
}
int root;for( i=1;i<=n;i++)if(flag[i]==0)
{
root=i;
break;
}
bfs(root);
while(m--)
{
scanf("%s%s",str1,str2);
i=find(str1);
j=find(str2);
k=lca(j,i);
int ans=0;
ans+=deg[i]-deg[k];
if(deg[k]!=deg[j])ans++;
printf("%d\n",ans);
}
}
return 0;
}
/*
7 7
2 1
4 2
5 2
3 1
6 3
7 3
*/