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


Problem Description
There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
 
Input
First line is a single integer T(T<=10), indicating the number of test cases.
  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.
 
Output
For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
 
Sample Input
2
3 2
1 2 10
3 1 15
1 2
2 3
 
2 2
1 2 100
1 2
2 1
 
Sample Output
10
25
100
100
 
思路:裸题,套模板即可。
代码实现如下:
 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
", cost[u] + cost[v] - 2 * cost[query(u, v)]);
80         }
81     }
82     return 0;
83 }
View Code

题目链接: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


Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
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.
 
Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.
 
Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.
 
Sample Input
5 3 2
1 3 2
2 4 3
5 2 3
1 4
4 5
 
Sample Output
Not connected
 
 
题目:
Distance Queries
Time Limit: 2000MS   Memory Limit: 30000K
Total Submissions: 15827   Accepted: 5576
Case Time Limit: 1000MS

Description

Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible!

Input

* Lines 1..1+M: Same format as "Navigation Nightmare"

* 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

* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.

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

Farms 2 and 6 are 20+3+13=36 apart.
 
思路:不要管这傻逼题面,输入就是裸的LCA输入格式,那个字母也不用管,可以使用%*s来读入字母。
代码实现如下:
 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
", cost[u] + cost[v] - 2 * cost[query(u, v)]);
80         }
81     }
82     return 0;
83 }
View Code

题目链接:http://poj.org/problem?id=1330

题目:

Nearest Common Ancestors
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 32969   Accepted: 16750

Description

A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:


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

The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,..., N. Each of the next N -1 lines contains a pair of integers that represent an edge --the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers whose nearest common ancestor is to be computed.

Output

Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.

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
", query(u, v));
81     }
82     return 0;
83 }
View Code


题目链接: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


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
 
思路:由于读入是字符串,因此我们需要借助map来将它转换成数字。同时此图也是给定了节点之间的方向,需要借助入度为0的节点来做根节点。看第二组数据和第三组数据我们发现此题的一个trick:从祖宗目录到子目录操作步数只需一步,然后我们可以发现,当所要到达的目录如果是当前目录的祖宗目录时,输出cost[u]-cost[query(u,v)],否则还要+1.
代码实现如下:
  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 }
View Code
题目:
Design the city

Time Limit: 1 Second      Memory Limit: 32768 KB

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("
");
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
", (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 }
View Code

至此感觉自己的LCA应该算是入门了,深入刷难题暑假再开始,毕竟现在要开始准备期末了,免得上学期专业课满绩点,高代全年级第一,这学期全部挂科然后挨骂Σ( ° △ °|||)︴

原文地址:https://www.cnblogs.com/Dillonh/p/9147601.html