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.
#include <cstdio>
#include <vector>
using namespace std; const int maxn = 4e4 + ;
int n, m, u, v, k;
int fa[maxn][], deep[maxn], cost[maxn]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << (k + )) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
int t;
scanf("%d", &t);
while(t--) {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
G[i].clear();
}
for(int i = ; i < n; i++) {
scanf("%d%d%d", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
while(m--) {
scanf("%d%d", &u, &v);
printf("%d\n", cost[u] + cost[v] - * cost[query(u, v)]);
}
}
return ;
}
题目链接: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
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 1e5 + ;
int n, m, q, u, v, k;
int fa[maxn][], deep[maxn], cost[maxn]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << ( + k)) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
while(~scanf("%d%d", &n, &m)) {
memset(cost, , sizeof(cost));
for(int i = ; i <= n; i++) {
G[i].clear();
}
for(int i = ; i < m; i++) {
scanf("%d%d%d%*s", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
scanf("%d", &q);
while(q--) {
scanf("%d%d", &u, &v);
printf("%d\n", cost[u] + cost[v] - * cost[query(u, v)]);
}
}
return ;
}
题目链接: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的节点做根节点。
代码实现如下:
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 1e4 + ;
int t, n, u, v, s;
int deep[maxn], fa[maxn][], in[maxn]; vector<int> G[maxn]; void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i];
if(v != p) {
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i <= n; i++) {
for(int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) <= n; j++) {
for(int i = ; i <= n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << ( + k)) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
for(int i = ; i <= n; i++) {
G[i].clear();
}
memset(in, , sizeof(in));
for(int i = ; i < n; i++) {
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
in[v]++;
}
for(int i = ; i <= n; i++) {
if(in[i] == ) {
s = i;
break;
}
}
dfs(s, , -);
lca();
scanf("%d%d", &u, &v);
printf("%d\n", query(u, v));
}
return ;
}
题目链接: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操作。
数据保证合法,一定存在一个根目录,每个目录都能从根目录访问到。
#include <map>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; const int maxn = 1e5 + ;
int t, n, m, cnt;
string s1, s2;
int cost[maxn], deep[maxn], fa[maxn][], in[maxn]; struct edge {
int v, l;
edge (int v = , int l = ) : v (v), l (l) {}
}; vector<edge> G[maxn];
map<string, int> mp; void init() {
cnt = ;
mp.clear();
memset (in, , sizeof (in) );
memset (cost, , sizeof (cost) );
for (int i = ; i <= n; i++) {
G[i].clear();
}
} void dfs (int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for (int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if (v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs (v, d + , u);
}
}
} void lca() {
for (int i = ; i <= n; i++) {
for (int j = ; ( << j) <= n; j++) {
fa[i][j] = -;
}
}
for (int j = ; ( << j) <= n; j++) {
for (int i = ; i <= n; i++) {
if (fa[i][j - ] != -) {
fa[i][j] = fa[fa[i][j - ]][j - ];
}
}
}
} int query (int u, int v) {
if (deep[u] < deep[v])
swap (u, v);
int k;
for (k = ; ( << ( + k) ) <= deep[u]; k++);
for (int i = k; i >= ; i--) {
if (deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if (u == v)
return u;
for (int i = k; i >= ; i--) {
if (fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
ios::sync_with_stdio (false);
cin.tie ();
cin >> t;
while (t--) {
cin >> n >> m;
init();
for (int i = ; i < n; i++) {
cin >> s1 >> s2;
if(mp.find(s1) == mp.end())
mp[s1] = ++cnt;
if(mp.find(s2) == mp.end())
mp[s2] = ++cnt;
in[mp[s1]]++;
G[mp[s1]].push_back (edge (mp[s2], ) );
G[mp[s2]].push_back (edge (mp[s1], ) );
}
int s;
for (int i = ; i <= n; i++) {
if (in[i] == ) {
s = i;
}
}
dfs (s, , -);
lca();
while (m--) {
cin >> s1 >> s2;
if(query(mp[s1], mp[s2]) == mp[s2]) {
cout <<cost[mp[s1]] - cost[mp[s2]] <<endl;
} else {
cout << cost[mp[s1]] - cost[query (mp[s1], mp[s2])] + << endl;
}
}
}
return ;
}
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即可。
代码实现如下:
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std; const int maxn = 5e4 + ;
int n, q, u, v, k;
int cost[maxn], deep[maxn], fa[maxn][]; struct edge {
int v, l;
edge(int v = , int l = ) : v(v), l(l) {}
}; vector<edge> G[maxn]; void init() {
memset(cost, , sizeof(cost));
for(int i = ; i < maxn; i++) {
G[i].clear();
}
} void dfs(int u, int d, int p) {
deep[u] = d;
fa[u][] = p;
for(int i = ; i < G[u].size(); i++) {
int v = G[u][i].v;
if(v != p) {
cost[v] = cost[u] + G[u][i].l;
dfs(v, d + , u);
}
}
} void lca() {
for(int i = ; i < n; i++) {
for(int j = ; ( << j) < n; j++) {
fa[i][j] = -;
}
}
for(int j = ; ( << j) < n; j++) {
for(int i = ; i < n; i++) {
if(fa[i][j-] != -) {
fa[i][j] = fa[fa[i][j-]][j-];
}
}
}
} int query(int u, int v) {
if(deep[u] < deep[v]) swap(u, v);
int k;
for(k = ; ( << k) <= deep[u]; k++);
for(int i = k; i >= ; i--) {
if(deep[u] - ( << i) >= deep[v]) {
u = fa[u][i];
}
}
if(u == v) return u;
for(int i = k; i >= ; i--) {
if(fa[u][i] != - && fa[u][i] != fa[v][i]) {
u = fa[u][i];
v = fa[v][i];
}
}
return fa[u][];
} int main() {
int flag = ;
while(~scanf("%d", &n)) {
if(flag) printf("\n");
flag = ;
init();
for(int i = ; i < n; i++) {
scanf("%d%d%d", &u, &v, &k);
G[u].push_back(edge(v, k));
G[v].push_back(edge(u, k));
}
dfs(, , -);
lca();
scanf("%d", &q);
while(q--) {
scanf("%d%d%d", &u, &v, &k);
printf("%d\n", (cost[u] + cost[v] - * cost[query(u, v)] + cost[u] + cost[k] - * cost[query(u, k)] + cost[v] + cost[k] - * cost[query(v, k)]) / );
}
}
return ;
}
至此感觉自己的LCA应该算是入门了,深入刷难题暑假再开始,毕竟现在要开始准备期末了,免得上学期专业课满绩点,高代全年级第一,这学期全部挂科然后挨骂Σ( ° △ °|||)︴
LCA入门题集小结的更多相关文章
- poj 1330(RMQ&LCA入门题)
传送门:Problem 1330 https://www.cnblogs.com/violet-acmer/p/9686774.html 参考资料: http://dongxicheng.org/st ...
- POJ1330(LCA入门题)
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 23388 Accept ...
- lca入门———树上倍增法(博文内含例题)
倍增求LCA: father[i][j]表示节点i往上跳2^j次后的节点 可以转移为 father[i][j]=father[father[i][j-1]][j-1] 整体思路: 先比较两个点的深度, ...
- poj 2524:Ubiquitous Religions(并查集,入门题)
Ubiquitous Religions Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 23997 Accepted: ...
- hrbustoj 1073:病毒(并查集,入门题)
病毒Time Limit: 1000 MS Memory Limit: 65536 KTotal Submit: 719(185 users) Total Accepted: 247(163 user ...
- ACM题集以及各种总结大全(转)
ACM题集以及各种总结大全! 虽然退役了,但是整理一下,供小弟小妹们以后切题方便一些,但由于近来考试太多,顾退役总结延迟一段时间再写!先写一下各种分类和题集,欢迎各位大牛路过指正. 一.ACM入门 关 ...
- ACM题集以及各种总结大全!
ACM题集以及各种总结大全! 虽然退役了,但是整理一下,供小弟小妹们以后切题方便一些,但由于近来考试太多,顾退役总结延迟一段时间再写!先写一下各种分类和题集,欢迎各位大牛路过指正. 一.ACM入门 关 ...
- Codevs 3287 货车运输 2013年NOIP全国联赛提高组(带权LCA+并查集+最大生成树)
3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 传送门 题目描述 Description A 国有 n 座 ...
- 数位dp题集
题集见大佬博客 不要62 入门题,检验刚才自己有没有看懂 注意一些细节. 的确挺套路的 #include<bits/stdc++.h> #define REP(i, a, b) for(r ...
随机推荐
- lintcode-15-全排列
全排列 给定一个数字列表,返回其所有可能的排列. 注意事项 你可以假设没有重复数字. 样例 给出一个列表[1,2,3],其全排列为: [ [1,2,3], [1,3,2], [2,1,3], [2,3 ...
- MVC4 DropDownList (二) — 省市联动
1.添加省份和城市类 //省份 public class Province { public int Id { get; set; } public string Name { get; set; } ...
- 3dContactPointAnnotationTool开发日志(二四)
添加了清空2d接触点的按钮,将输出的2d接触点的单位变成了像素,原点在图像的左下角. 对于obj文件的适配更加多样化了.
- 重要的几个按键Tab Ctrl+c Ctrl+d
1.Tab按键具有命令补齐和档案补齐的功能,重点是可以避免我们打错命令或者文件名,但是Tab按键在不同的地方输入会有不同的结果 试着多按几下,或者连按两次相信你会发现新大陆 a.Tab接在一串指令的第 ...
- tomcat执行shutdown.sh进程残留的解决办法
我们执行shutdown.sh指令的时候有时会发现进程并没有被关掉而是越来越多,这种情况一般是项目造成的,具体原因未去调查.由于tomcat自己有相应的保护机制,所以我们只需要强制结束其进程即可,下面 ...
- 【bzoj1634】[Usaco2007 Jan]Protecting the Flowers 护花 贪心
题目描述 Farmer John went to cut some wood and left N (2 <= N <= 100,000) cows eating the grass, a ...
- lalala
<script type="text/javascript"> var a_idx = 0; var b_idx = 0; var a = new Array(&quo ...
- [JLOI2014]松鼠的新家 树上差分
差分 一开始竟然想分情况讨论来差分,然后发现各自情况要分析, 就是为了解决中间节点重复计算的问题, 结果 最后一想,中间重复计算了一次,那我最后减掉不就好了么,,, 那这就是一道差分裸题了(这是唯一不 ...
- POJ3304:Segments——题解
http://poj.org/problem?id=3304 题目大意:给n条线段,求是否存在一条直线,将所有线段投影到上面,使得所有投影至少交于一点. ——————————————————————— ...
- POJ1273:Drainage Ditches——题解
http://poj.org/problem?id=1273 题目大意: n点m边网络流,求1-n最大流. —————————————— 网络流板子,切了. #include <cstdio&g ...