LCA入门题集小结
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586
题目:
How far away ?
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 21500 Accepted Submission(s): 8471
For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
1 #include <cstdio> 2 #include <vector> 3 using namespace std; 4 5 const int maxn = 4e4 + 7; 6 int n, m, u, v, k; 7 int fa[maxn][30], deep[maxn], cost[maxn]; 8 9 struct edge { 10 int v, l; 11 edge(int v = 0, int l = 0) : v(v), l(l) {} 12 }; 13 14 vector<edge> G[maxn]; 15 16 void dfs(int u, int d, int p) { 17 deep[u] = d; 18 fa[u][0] = p; 19 for(int i = 0; i < G[u].size(); i++) { 20 int v = G[u][i].v; 21 if(v != p) { 22 cost[v] = cost[u] + G[u][i].l; 23 dfs(v, d + 1, u); 24 } 25 } 26 } 27 28 void lca() { 29 for(int i = 1; i <= n; i++) { 30 for(int j = 1; (1 << j) <= n; j++) { 31 fa[i][j] = -1; 32 } 33 } 34 for(int j = 1; (1 << j) <= n; j++) { 35 for(int i = 1; i <= n; i++) { 36 if(fa[i][j-1] != -1) { 37 fa[i][j] = fa[fa[i][j-1]][j-1]; 38 } 39 } 40 } 41 } 42 43 int query(int u, int v) { 44 if(deep[u] < deep[v]) swap(u, v); 45 int k; 46 for(k = 0; (1 << (k + 1)) <= deep[u]; k++); 47 for(int i = k; i >= 0; i--) { 48 if(deep[u] - (1 << i) >= deep[v]) { 49 u = fa[u][i]; 50 } 51 } 52 if(u == v) return u; 53 for(int i = k; i >= 0; i--) { 54 if(fa[u][i] != -1 && fa[u][i] != fa[v][i]) { 55 u = fa[u][i]; 56 v = fa[v][i]; 57 } 58 } 59 return fa[u][0]; 60 } 61 62 int main() { 63 int t; 64 scanf("%d", &t); 65 while(t--) { 66 scanf("%d%d", &n, &m); 67 for(int i = 1; i <= n; i++) { 68 G[i].clear(); 69 } 70 for(int i = 1; i < n; i++) { 71 scanf("%d%d%d", &u, &v, &k); 72 G[u].push_back(edge(v, k)); 73 G[v].push_back(edge(u, k)); 74 } 75 dfs(1, 0, -1); 76 lca(); 77 while(m--) { 78 scanf("%d%d", &u, &v); 79 printf("%d\n", cost[u] + cost[v] - 2 * cost[query(u, v)]); 80 } 81 } 82 return 0; 83 }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874
题目:
Connections between cities
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 13879 Accepted Submission(s): 3159
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
Time Limit: 2000MS | Memory Limit: 30000K | |
Total Submissions: 15827 | Accepted: 5576 | |
Case Time Limit: 1000MS |
Description
Input
* Line 2+M: A single integer, K. 1 <= K <= 10,000
* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.
Output
Sample Input
7 6 1 6 13 E 6 3 9 E 3 5 7 S 4 1 3 N 2 4 20 W 4 7 2 S 3 1 6 1 4 2 6
Sample Output
13 3 36
Hint
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 1e5 + 7; 7 int n, m, q, u, v, k; 8 int fa[maxn][30], deep[maxn], cost[maxn]; 9 10 struct edge { 11 int v, l; 12 edge(int v = 0, int l = 0) : v(v), l(l) {} 13 }; 14 15 vector<edge> G[maxn]; 16 17 void dfs(int u, int d, int p) { 18 deep[u] = d; 19 fa[u][0] = p; 20 for(int i = 0; i < G[u].size(); i++) { 21 int v = G[u][i].v; 22 if(v != p) { 23 cost[v] = cost[u] + G[u][i].l; 24 dfs(v, d + 1, u); 25 } 26 } 27 } 28 29 void lca() { 30 for(int i = 1; i <= n; i++) { 31 for(int j = 1; (1 << j) <= n; j++) { 32 fa[i][j] = -1; 33 } 34 } 35 for(int j = 1; (1 << j) <= n; j++) { 36 for(int i = 1; i <= n; i++) { 37 if(fa[i][j-1] != -1) { 38 fa[i][j] = fa[fa[i][j-1]][j-1]; 39 } 40 } 41 } 42 } 43 44 int query(int u, int v) { 45 if(deep[u] < deep[v]) swap(u, v); 46 int k; 47 for(k = 0; (1 << (1 + k)) <= deep[u]; k++); 48 for(int i = k; i >= 0; i--) { 49 if(deep[u] - (1 << i) >= deep[v]) { 50 u = fa[u][i]; 51 } 52 } 53 if(u == v) return u; 54 for(int i = k; i >= 0; i--) { 55 if(fa[u][i] != -1 && fa[u][i] != fa[v][i]) { 56 u = fa[u][i]; 57 v = fa[v][i]; 58 } 59 } 60 return fa[u][0]; 61 } 62 63 int main() { 64 while(~scanf("%d%d", &n, &m)) { 65 memset(cost, 0, sizeof(cost)); 66 for(int i = 0; i <= n; i++) { 67 G[i].clear(); 68 } 69 for(int i = 0; i < m; i++) { 70 scanf("%d%d%d%*s", &u, &v, &k); 71 G[u].push_back(edge(v, k)); 72 G[v].push_back(edge(u, k)); 73 } 74 dfs(1, 0, -1); 75 lca(); 76 scanf("%d", &q); 77 while(q--) { 78 scanf("%d%d", &u, &v); 79 printf("%d\n", cost[u] + cost[v] - 2 * cost[query(u, v)]); 80 } 81 } 82 return 0; 83 }
题目链接:http://poj.org/problem?id=1330
题目:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 32969 | Accepted: 16750 |
Description
In the figure, each node is labeled with an integer from {1, 2,...,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
Output
Sample Input
2 16 1 14 8 5 10 16 5 9 4 6 8 4 4 10 1 13 6 15 10 11 6 7 10 2 16 3 8 1 16 12 16 7 5 2 3 3 4 3 1 1 5 3 5
Sample Output
4 3
思路:裸的LCA,不过要注意它的节点之间是有向的,所以需要用一个数组来储存入度,以入度为0的节点做根节点。
代码实现如下:
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 1e4 + 7; 7 int t, n, u, v, s; 8 int deep[maxn], fa[maxn][30], in[maxn]; 9 10 vector<int> G[maxn]; 11 12 void dfs(int u, int d, int p) { 13 deep[u] = d; 14 fa[u][0] = p; 15 for(int i = 0; i < G[u].size(); i++) { 16 int v = G[u][i]; 17 if(v != p) { 18 dfs(v, d + 1, u); 19 } 20 } 21 } 22 23 void lca() { 24 for(int i = 1; i <= n; i++) { 25 for(int j = 1; (1 << j) <= n; j++) { 26 fa[i][j] = -1; 27 } 28 } 29 for(int j = 1; (1 << j) <= n; j++) { 30 for(int i = 1; i <= n; i++) { 31 if(fa[i][j-1] != -1) { 32 fa[i][j] = fa[fa[i][j-1]][j-1]; 33 } 34 } 35 } 36 } 37 38 int query(int u, int v) { 39 if(deep[u] < deep[v]) swap(u, v); 40 int k; 41 for(k = 0; (1 << (1 + k)) <= deep[u]; k++); 42 for(int i = k; i >= 0; i--) { 43 if(deep[u] - (1 << i) >= deep[v]) { 44 u = fa[u][i]; 45 } 46 } 47 if(u == v) return u; 48 for(int i = k; i >= 0; i--) { 49 if(fa[u][i] != -1 && fa[u][i] != fa[v][i]) { 50 u = fa[u][i]; 51 v = fa[v][i]; 52 } 53 } 54 return fa[u][0]; 55 } 56 57 int main() { 58 scanf("%d", &t); 59 while(t--) { 60 scanf("%d", &n); 61 for(int i = 0; i <= n; i++) { 62 G[i].clear(); 63 } 64 memset(in, 0, sizeof(in)); 65 for(int i = 1; i < n; i++) { 66 scanf("%d%d", &u, &v); 67 G[u].push_back(v); 68 G[v].push_back(u); 69 in[v]++; 70 } 71 for(int i = 1; i <= n; i++) { 72 if(in[i] == 0) { 73 s = i; 74 break; 75 } 76 } 77 dfs(s, 0, -1); 78 lca(); 79 scanf("%d%d", &u, &v); 80 printf("%d\n", query(u, v)); 81 } 82 return 0; 83 }
题目链接: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): 3035 Accepted Submission(s): 848
这里我们简化一下问题,假设只有一个根目录,CD操作也只有两种方式:
1. CD 当前目录名\...\目标目录名 (中间可以包含若干目录,保证目标目录通过绝对路径可达)
2. CD .. (返回当前目录的上级目录)
现在给出当前目录和一个目标目录,请问最少需要几次CD操作才能将当前目录变成目标目录?
每个样例首先一行是两个整数N和M(1<=N,M<=100000),表示有N个目录和M个询问;
接下来N-1行每行两个目录名A B(目录名是只含有数字或字母,长度小于40的字符串),表示A的父目录是B。
最后M行每行两个目录名A B,表示询问将当前目录从A变成B最少要多少次CD操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
1 #include <map> 2 #include <vector> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 8 const int maxn = 1e5 + 7; 9 int t, n, m, cnt; 10 string s1, s2; 11 int cost[maxn], deep[maxn], fa[maxn][30], in[maxn]; 12 13 struct edge { 14 int v, l; 15 edge (int v = 0, int l = 0) : v (v), l (l) {} 16 }; 17 18 vector<edge> G[maxn]; 19 map<string, int> mp; 20 21 void init() { 22 cnt = 0; 23 mp.clear(); 24 memset (in, 0, sizeof (in) ); 25 memset (cost, 0, sizeof (cost) ); 26 for (int i = 0; i <= n; i++) { 27 G[i].clear(); 28 } 29 } 30 31 void dfs (int u, int d, int p) { 32 deep[u] = d; 33 fa[u][0] = p; 34 for (int i = 0; i < G[u].size(); i++) { 35 int v = G[u][i].v; 36 if (v != p) { 37 cost[v] = cost[u] + G[u][i].l; 38 dfs (v, d + 1, u); 39 } 40 } 41 } 42 43 void lca() { 44 for (int i = 1; i <= n; i++) { 45 for (int j = 1; (1 << j) <= n; j++) { 46 fa[i][j] = -1; 47 } 48 } 49 for (int j = 1; (1 << j) <= n; j++) { 50 for (int i = 1; i <= n; i++) { 51 if (fa[i][j - 1] != -1) { 52 fa[i][j] = fa[fa[i][j - 1]][j - 1]; 53 } 54 } 55 } 56 } 57 58 int query (int u, int v) { 59 if (deep[u] < deep[v]) 60 swap (u, v); 61 int k; 62 for (k = 0; (1 << (1 + k) ) <= deep[u]; k++); 63 for (int i = k; i >= 0; i--) { 64 if (deep[u] - (1 << i) >= deep[v]) { 65 u = fa[u][i]; 66 } 67 } 68 if (u == v) 69 return u; 70 for (int i = k; i >= 0; i--) { 71 if (fa[u][i] != -1 && fa[u][i] != fa[v][i]) { 72 u = fa[u][i]; 73 v = fa[v][i]; 74 } 75 } 76 return fa[u][0]; 77 } 78 79 int main() { 80 ios::sync_with_stdio (false); 81 cin.tie (0); 82 cin >> t; 83 while (t--) { 84 cin >> n >> m; 85 init(); 86 for (int i = 1; i < n; i++) { 87 cin >> s1 >> s2; 88 if(mp.find(s1) == mp.end()) 89 mp[s1] = ++cnt; 90 if(mp.find(s2) == mp.end()) 91 mp[s2] = ++cnt; 92 in[mp[s1]]++; 93 G[mp[s1]].push_back (edge (mp[s2], 1) ); 94 G[mp[s2]].push_back (edge (mp[s1], 1) ); 95 } 96 int s; 97 for (int i = 1; i <= n; i++) { 98 if (in[i] == 0) { 99 s = i; 100 } 101 } 102 dfs (s, 0, -1); 103 lca(); 104 while (m--) { 105 cin >> s1 >> s2; 106 if(query(mp[s1], mp[s2]) == mp[s2]) { 107 cout <<cost[mp[s1]] - cost[mp[s2]] <<endl; 108 } else { 109 cout << cost[mp[s1]] - cost[query (mp[s1], mp[s2])] + 1 << endl; 110 } 111 } 112 } 113 return 0; 114 }
Cerror is the mayor of city HangZhou. As you may know, the traffic system of this city is so terrible, that there are traffic jams everywhere. Now, Cerror finds out that the main reason of them is the poor design of the roads distribution, and he want to change this situation.
In order to achieve this project, he divide the city up to N regions which can be viewed as separate points. He thinks that the best design is the one that connect all region with shortest road, and he is asking you to check some of his designs.
Now, he gives you an acyclic graph representing his road design, you need to find out the shortest path to connect some group of three regions.
Input
The input contains multiple test cases! In each case, the first line contian a interger N (1 < N < 50000), indicating the number of regions, which are indexed from 0 to N-1. In each of the following N-1 lines, there are three interger Ai, Bi, Li (1 < Li < 100) indicating there's a road with length Li between region Ai and region Bi. Then an interger Q (1 < Q < 70000), the number of group of regions you need to check. Then in each of the following Q lines, there are three interger Xi, Yi, Zi, indicating the indices of the three regions to be checked.
Process to the end of file.
Output
Q lines for each test case. In each line output an interger indicating the minimum length of path to connect the three regions.
Output a blank line between each test cases.
Sample Input
4 0 1 1 0 2 1 0 3 1 2 1 2 3 0 1 2 5 0 1 1 0 2 1 1 3 1 1 4 1 2 0 1 2 1 0 3
Sample Output
3 2 2 2
思路:将所给的x,y,z分别两两求一次lca,然后除2即可。
代码实现如下:
1 #include <cstdio> 2 #include <vector> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 5e4 + 7; 7 int n, q, u, v, k; 8 int cost[maxn], deep[maxn], fa[maxn][30]; 9 10 struct edge { 11 int v, l; 12 edge(int v = 0, int l = 0) : v(v), l(l) {} 13 }; 14 15 vector<edge> G[maxn]; 16 17 void init() { 18 memset(cost, 0, sizeof(cost)); 19 for(int i = 0; i < maxn; i++) { 20 G[i].clear(); 21 } 22 } 23 24 void dfs(int u, int d, int p) { 25 deep[u] = d; 26 fa[u][0] = p; 27 for(int i = 0; i < G[u].size(); i++) { 28 int v = G[u][i].v; 29 if(v != p) { 30 cost[v] = cost[u] + G[u][i].l; 31 dfs(v, d + 1, u); 32 } 33 } 34 } 35 36 void lca() { 37 for(int i = 0; i < n; i++) { 38 for(int j = 1; (1 << j) < n; j++) { 39 fa[i][j] = -1; 40 } 41 } 42 for(int j = 1; (1 << j) < n; j++) { 43 for(int i = 0; i < n; i++) { 44 if(fa[i][j-1] != -1) { 45 fa[i][j] = fa[fa[i][j-1]][j-1]; 46 } 47 } 48 } 49 } 50 51 int query(int u, int v) { 52 if(deep[u] < deep[v]) swap(u, v); 53 int k; 54 for(k = 0; (1 << k) <= deep[u]; k++); 55 for(int i = k; i >= 0; i--) { 56 if(deep[u] - (1 << i) >= deep[v]) { 57 u = fa[u][i]; 58 } 59 } 60 if(u == v) return u; 61 for(int i = k; i >= 0; i--) { 62 if(fa[u][i] != -1 && fa[u][i] != fa[v][i]) { 63 u = fa[u][i]; 64 v = fa[v][i]; 65 } 66 } 67 return fa[u][0]; 68 } 69 70 int main() { 71 int flag = 0; 72 while(~scanf("%d", &n)) { 73 if(flag) printf("\n"); 74 flag = 1; 75 init(); 76 for(int i = 1; i < n; i++) { 77 scanf("%d%d%d", &u, &v, &k); 78 G[u].push_back(edge(v, k)); 79 G[v].push_back(edge(u, k)); 80 } 81 dfs(0, 0, -1); 82 lca(); 83 scanf("%d", &q); 84 while(q--) { 85 scanf("%d%d%d", &u, &v, &k); 86 printf("%d\n", (cost[u] + cost[v] - 2 * cost[query(u, v)] + cost[u] + cost[k] - 2 * cost[query(u, k)] + cost[v] + cost[k] - 2 * cost[query(v, k)]) / 2); 87 } 88 } 89 return 0; 90 }
至此感觉自己的LCA应该算是入门了,深入刷难题暑假再开始,毕竟现在要开始准备期末了,免得上学期专业课满绩点,高代全年级第一,这学期全部挂科然后挨骂Σ( ° △ °|||)︴