http://acm.hdu.edu.cn/showproblem.php?pid=4547
CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 3020 Accepted Submission(s): 841
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
2013金山西山居创意游戏程序挑战赛——初赛(1)
Recommend
liuyiding | We have carefully selected several similar problems for you: 6297 6296 6295 6294 6293
LCA_倍增
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<iostream>
#include<string>
#include<map>
using namespace std;
const int maxn = 1e5 + 10;
map<string, int> mp;
int n, m, dep[maxn], fa[maxn][20], rt, head[maxn], sz = 0, Log[maxn];
bool f[maxn];
struct edge {
int v, w, nx;
}e[maxn];
string s1, s2;
inline void add(int u, int v) {
e[++sz].v = v; e[sz].nx = head[u]; head[u] = sz;
}
void init();
void dfs(int x) {
for (int i = 1; i <= Log[n]; i++) {
if (!fa[x][i - 1]) break;
fa[x][i] = fa[fa[x][i-1]][i - 1];
}
for (int i = head[x]; i != -1; i = e[i].nx) {
int v = e[i].v; dep[v] = dep[x] + 1; dfs(v);
}
}
int lca(int u, int v) {
if (dep[u] < dep[v]) swap(u, v);
int d = dep[u] - dep[v];
for (int i = 0; i <= Log[d]; i++) {
if (d >> i & 1) u = fa[u][i];
}
if (u == v) return u;
for (int i = Log[n]; i >= 0; i--) {
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
int main() {
int T;
Log[0] = -1;
for (int i = 1; i <= maxn - 10; i++) Log[i] = Log[i >> 1] + 1;
scanf("%d", &T); bool flag = 0;
while (T--) {
//if (flag) printf("\n");
flag = 1;
scanf("%d %d", &n, &m);
init(); int tot = 0;
for (int i = 1; i < n; i++) {
cin >> s1 >> s2;
if (!mp[s1]) mp[s1] = ++tot;
if (!mp[s2]) mp[s2] = ++tot;
fa[mp[s1]][0] = mp[s2]; f[mp[s1]] = 1; add(mp[s2], mp[s1]);
}
for (int i = 1; i <= n; i++) if (!f[i]) rt = i;
dep[rt] = 0; dfs(rt);
while (m--) {
cin >> s1 >> s2;
int u = mp[s1], v = mp[s2], t = lca(u, v);
if (u == v) puts("0");
else if (u == t) puts("1");
else if (v == t) printf("%d\n", dep[u] - dep[v]);
else printf("%d\n", dep[u] - dep[t] + 1);
}
}
return 0;
}
void init()
{
sz = 0;
memset(f, 0, sizeof f);
memset(fa, 0, sizeof fa);
memset(head, -1, sizeof head);
mp.clear();
}