CD操作
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 551 Accepted Submission(s): 161
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 <cstdio> #include <cstring> #include <algorithm> #include <string> #include <map> using namespace std; #pragma warning(disable : 4996) const int MAXN = 100005; typedef struct Edge { int v; int w; int next; int lca; }Edge; typedef struct Query { int u; int v; int lca; }Query; Query q[MAXN]; int cnt, edge_head[MAXN], ask_head[MAXN]; int father[MAXN], dist[MAXN]; bool visited[MAXN]; Edge edge[2 * MAXN], ask[2 * MAXN]; int in[MAXN]; map<string, int>Map; int num; int Getnum(string str) { if(Map.find(str) == Map.end()) { Map[str] = num++; } return Map[str]; } int find(int x) { if (x != father[x]) { father[x] = find(father[x]); } return father[x]; } void add_edge(int x, int y, int z) { edge[cnt].v = y; edge[cnt].w = z; edge[cnt].next = edge_head[x]; edge_head[x] = cnt++; } void add_ask(int x, int y, int cast) { ask[cnt].v = y; ask[cnt].w = cast; ask[cnt].next = ask_head[x]; ask_head[x] = cnt++; } void Tarjan(int k) { visited[k] = true; for (int i = ask_head[k]; i != 0; i = ask[i].next) { if (visited[ask[i].v]) { ask[i].lca = find(ask[i].v); q[ask[i].w].lca = ask[i].lca; } } for (int i = edge_head[k]; i != 0; i = edge[i].next) { if (!visited[edge[i].v]) { dist[edge[i].v] = dist[k] + edge[i].w; Tarjan(edge[i].v); edge[i].v = find(edge[i].v); father[edge[i].v] = k; } } } int main() { freopen("in.txt", "r", stdin); int i, m, n; int x, y; int t; int ans, root; string s1, s2; scanf("%d", &t); while (t--) { scanf("%d %d", &n, &m); for (i = 1; i <= n; i++) { edge_head[i] = ask_head[i] = 0; father[i] = i; visited[i] = false; in[i] = 0; } Map.clear(); cnt = num = 1; for (i = 1; i < n; i++) { cin >> s1 >> s2; x = Getnum(s1); y = Getnum(s2); //cout << x << " " << y << endl; add_edge(x, y, 1); add_edge(y, x, 1); in[x]++; } cnt = 1; for (i = 1; i <= m; i++) { cin >> s1 >> s2; x = Getnum(s1); y = Getnum(s2); add_ask(x, y, i); add_ask(y, x, i); q[i].u = x; q[i].v = y; } root = 0; for(int i = 1; i <= n; i++) { if(in[i] == 0) { root = i; break; } } //cout << root << endl; dist[root] = 0; Tarjan(root); for (int i = 1; i <= m; i++) { ans = dist[q[i].u] - dist[q[i].lca]; if(q[i].lca != q[i].v) { ans++; } if(q[i].u == q[i].v) { ans = 0; } printf("%d\n", ans); } } return 0; }